install -m755 etc/bash_completion.d/mic.sh $(CURDIR)/debian/tmp/etc/bash_completion.d/
install -m755 etc/zsh_completion.d/_mic $(CURDIR)/debian/tmp/etc/zsh_completion.d/_mic
python3 setup.py install --root=$(CURDIR)/debian/tmp --prefix=/usr
-
+ # Installing mic py2 code
+ mkdir -p $(CURDIR)/debian/tmp/usr/lib/mic/mic_py2
+ cp -rp mic_py2/* $(CURDIR)/debian/tmp/usr/lib/mic/mic_py2
override_dh_installchangelogs:
dh_installchangelogs ChangeLog
override_dh_auto_test:
--- /dev/null
+[common]
+; general settings
+distro_name = Tizen
+
+plugin_dir = /usr/lib/mic/plugins
+
+[create]
+; settings for create subcommand
+tmpdir= /var/tmp/mic
+cachedir= /var/tmp/mic/cache
+outdir= ./mic-output
+runtime=bootstrap
+#use_mic_in_bootstrap = yes
+
+pkgmgr = auto
+
+# to set global proxy for repos
+#proxy = http://proxy.yourcompany.com:8080/
+#no_proxy = localhost,127.0.0.0/8,.yourcompany.com
+
+# prefix will be added in front of generated files
+#name_prefix = output
+
+# to skip all ssl verification for repos
+#ssl_verify = no
+
+[convert]
+; settings for convert subcommand
+
+[chroot]
+; settings for chroot subcommand
+
+[bootstrap]
+rootdir=/var/tmp/mic-bootstrap
+packages=mic-bootstrap-x86-arm
+
--- /dev/null
+#! /usr/bin/python2
+
+#Copyright (c) 2011 Intel, Inc.
+#
+#This program is free software; you can redistribute it and/or modify it
+#under the terms of the GNU General Public License as published by the Free
+#Software Foundation; version 2 of the License
+#
+#This program is distributed in the hope that it will be useful, but
+#WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# pylint: disable-msg=E0611, E1101, R0201
+# E0611: no name in module, some attributes are set during running, so ignore it
+# E1101: %s %r has no %r member, some attributes are set during running,
+# so ignore it
+# R0201: Method could be a function
+
+"""
+ This mudule is entry for mic.
+ It defines a class named MicCmd inheriting Cmdln, and supplies interfaces like
+ 'create, chroot, convert' and also some parameters for command 'mic'.
+"""
+import os
+import signal
+import sys
+import errno
+
+from argparse import ArgumentParser, SUPPRESS
+
+from mic import msger, __version__ as VERSION
+from mic.utils import misc, errors
+from mic.conf import configmgr
+from mic.plugin import pluginmgr
+from mic.helpformat import MICHelpFormatter, subparser
+
+
+@subparser
+def chroot_parser(parser):
+ """chroot into an image
+
+ Examples:
+ mic chroot platform.img
+ mic chroot platform.img ls
+ """
+ parser.add_argument('imagefile', help='Path of image file')
+ parser.add_argument('-s', '--saveto', action = 'store', dest = 'saveto', default = None,
+ help = "Save the unpacked image to specified dir")
+ parser.add_argument('-c', '--cmd', dest = 'cmd', default = None,
+ help = "command which will be executed in chroot environment")
+ parser.set_defaults(alias="ch")
+ return parser
+
+@subparser
+def create_parser(parser):
+ """create an image
+ Examples:
+ $ mic -d -v create auto handset_blackbay.ks
+ $ mic -d -v cr loop handset_blackbay.ks --logfile=mic.log
+ """
+
+ parent_parser = ArgumentParser(add_help=False)
+ 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')
+ 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',
+ default=None, help='Output directory')
+ parent_parser.add_argument('-A', '--arch', dest='arch', default=None,
+ help='Specify repo architecture')
+ parent_parser.add_argument('--release', dest='release', default=None, metavar='RID',
+ help='Generate a release of RID with all necessary'
+ ' files, when @BUILD_ID@ is contained in '
+ 'kickstart file, it will be replaced by RID')
+ parent_parser.add_argument("--record-pkgs", dest="record_pkgs", default=None,
+ help='Record the info of installed packages, '
+ 'multiple values can be specified which '
+ 'joined by ",", valid values: "name", '
+ '"content", "license", "vcs"')
+ parent_parser.add_argument('--pkgmgr', dest='pkgmgr', default=None,
+ help='Specify backend package manager')
+ parent_parser.add_argument('--local-pkgs-path', dest='local_pkgs_path', default=None,
+ help='Path for local pkgs(rpms) to be installed')
+ parent_parser.add_argument('--runtime', dest='runtime', default=None,
+ help='Specify runtime mode, avaiable: bootstrap')
+ # --taring-to is alias to --pack-to
+ parent_parser.add_argument('--taring-to', dest='pack_to', default=None,
+ help=SUPPRESS)
+ parent_parser.add_argument('--pack-to', dest='pack_to', default=None,
+ help='Pack the images together into the specified'
+ ' achive, extension supported: .zip, .tar, '
+ '.tar.gz, .tar.bz2, etc. by default, .tar '
+ 'will be used')
+ parent_parser.add_argument('--copy-kernel', action='store_true', dest='copy_kernel',
+ help='Copy kernel files from image /boot directory'
+ ' to the image output directory.')
+ parent_parser.add_argument('--install-pkgs', action='store', dest='install_pkgs', default=None,
+ help='Specify what type of packages to be installed,'
+ ' valid: source, debuginfo, debugsource')
+ parent_parser.add_argument('--check-pkgs', action='store', dest='check_pkgs', default=[],
+ help='Check if given packages would be installed, '
+ 'packages should be separated by comma')
+ parent_parser.add_argument('--tmpfs', action='store_true', dest='enabletmpfs',
+ help='Setup tmpdir as tmpfs to accelerate, experimental'
+ ' feature, use it if you have more than 4G memory')
+ parent_parser.add_argument('--repourl', action='append', dest='repourl', default=[],
+ help=SUPPRESS)
+ parent_parser.add_argument('-R', '--repo', action='append',
+ dest='repo', default=[],
+ help=SUPPRESS)
+ parent_parser.add_argument('--ignore-ksrepo', action='store_true',
+ dest='ignore_ksrepo', default=False,
+ help=SUPPRESS)
+ parent_parser.add_argument('--strict-mode', action='store_true',
+ 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',
+ help='verbose output')
+ 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')
+ parent_parser.add_argument('--skip-set-hosts', action='store_true', dest='skip_set_hosts', default=False, help='choose to skip set hosts by mic')
+ parent_parser.add_argument('--postscripts-maxruntime', dest='postscripts_maxruntime', default=120, help='max run time for post scripts')
+ parent_parser.add_argument('--block-recommends', action='store_true', dest='block_recommends', default=False, help='Do not install recommended packages')
+
+ parser.set_defaults(alias="cr")
+
+ subparsers = parser.add_subparsers(title='Subcommands', dest='subcommand')
+ auto_parser = subparsers.add_parser('auto', parents=[parent_parser], help='auto detect image type from magic header')
+
+ fs_parser = subparsers.add_parser('fs', parents=[parent_parser],
+ help='create fs image')
+ fs_parser.add_argument("--include-src", dest = "include_src",action = "store_true",
+ default = False, help = "Generate a image with source rpms included")
+
+ loop_parser = subparsers.add_parser('loop', parents=[parent_parser], help='create loop image')
+
+ loop_parser.add_argument("--compress-disk-image", dest="compress_image",
+ choices=("gz", "bz2"), default=None,
+ help="Same with --compress-image")
+ # alias to compress-image for compatibility
+ loop_parser.add_argument("--compress-image", dest="compress_image",
+ choices=("gz", "bz2"), default=None,
+ help="Compress all loop images with 'gz' or 'bz2'")
+ loop_parser.add_argument("--shrink", action='store_true', default=False,
+ help="Whether to shrink loop images to minimal size")
+
+ qcow_parser = subparsers.add_parser('qcow', parents=[parent_parser], help='create qcow image')
+
+ raw_parser = subparsers.add_parser('raw', parents=[parent_parser], help='create raw image')
+
+ raw_parser.add_argument("--compress-disk-image", dest="compress_image",
+ choices=("gz", "bz2"), default=None,
+ help="Same with --compress-image")
+ raw_parser.add_argument("--compress-image", dest="compress_image",
+ choices=("gz", "bz2"), default = None,
+ help="Compress all raw images before package")
+ raw_parser.add_argument("--generate-bmap", action="store_true", default = None,
+ help="also generate the block map file")
+ raw_parser.add_argument("--fstab-entry", dest="fstab_entry", choices=("name", "uuid"), default="uuid",
+ help="Set fstab entry, 'name' means using device names, "
+ "'uuid' means using filesystem uuid")
+ return parser
+
+def main(argv):
+ """Script entry point."""
+
+ def print_version():
+ """log name, verion, hostname"""
+
+ name = 'mic'
+ msger.raw("%s %s (%s)" % (name,
+ VERSION,
+ misc.get_hostname_distro_str()))
+
+ def has_parameter(arg, arglist):
+ """
+ Helper function.
+ Check if argument requires parameter by analyzing
+ its action. Parameter is required only for 'store' and 'append' actions
+ """
+ if arg.startswith('-'):
+ for args in arglist:
+ if arg in (args['short'], args['long']):
+ if args.get('action') in (None, 'store', 'append'):
+ 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"
+ parser = ArgumentParser(description=description, epilog=epilog,
+ formatter_class=MICHelpFormatter)
+
+ # List of global arguments
+ # The main purpose of this structure is to contain arguments
+ # of add_argument. This is used to do aliasing properly
+ # (see code under the comment 'replace aliases with real commands')
+ global_args = [{'short': '-V', 'long': '--version', 'action': 'version',
+ 'version': '%(prog)s ' + VERSION},
+ {'short': '-d', 'long': '--debug', 'action': 'store_true',
+ 'help': 'debug output'},
+ {'short': '-v', 'long': '--verbose', 'action': 'store_true',
+ 'help': 'verbose output'},
+ {'short': '-i', 'long': '--interactive', 'action': 'store_true',
+ 'dest': 'interactive', 'default': 'True', 'help': 'interactive output'},
+ {'short': '', 'long': '--non-interactive', 'action': 'store_false',
+ 'dest': 'interactive', 'default': 'True', 'help': 'non-interactive output'},
+ ]
+
+ for args in global_args:
+ parser_kwargs = {}
+ for key in ('action', 'help', 'version', 'default', 'dest'):
+ if key in args:
+ parser_kwargs[key] = args[key]
+
+ if args['short'] is '':
+ parser.add_argument(args['long'], **parser_kwargs)
+ else:
+ parser.add_argument(args['short'], args['long'], **parser_kwargs)
+
+ # hacked by the request of cmdln lovers
+ parser.format_usage = parser.format_help
+
+ # Create parsers for subcommands
+ subparsers = parser.add_subparsers(title='subcommands')
+
+ # collect aliases
+ aliases = {}
+ for name, obj in globals().iteritems():
+ if name.endswith('_parser') and callable(obj):
+ aliases[obj(subparsers).get_default('alias')] = name.split('_')[0]
+
+ # replace aliases with real commands
+ for i, arg in enumerate(argv[1:]):
+ if not arg.startswith('-'):
+ # argv[i] is previous argument to arg
+ if not has_parameter(argv[i], global_args) and arg in aliases:
+ argv[i+1] = aliases[arg]
+ break
+
+ # Parse arguments
+ args = parser.parse_args(argv[1:])
+
+ if args.interactive:
+ msger.enable_interactive()
+ else:
+ msger.disable_interactive()
+
+ if args.verbose:
+ msger.set_loglevel('VERBOSE')
+
+ if args.debug:
+ try:
+ import rpm
+ rpm.setVerbosity(rpm.RPMLOG_DEBUG)
+ except ImportError:
+ pass
+
+ msger.set_loglevel('DEBUG')
+
+ print_version()
+
+ # Import target module and call 'main' from it
+ module = __import__("mic.%s" % args.module, fromlist=[args.module])
+ return module.main(parser, args, argv[1:])
+
+
+if __name__ == "__main__":
+ try:
+ sys.exit(main(sys.argv))
+ except KeyboardInterrupt:
+ msger.error('\n^C catched, program aborted.')
+ except IOError as ioerr:
+ # catch 'no space left' exception, etc
+ if ioerr.errno == errno.ENOSPC:
+ msger.error('\nNo space left on device')
+ raise
+ except errors.Usage as usage:
+ msger.error(str(usage))
+ except errors.Abort as msg:
+ msger.info(str(msg))
+ except errors.CreatorError as err:
+ if msger.get_loglevel() == 'DEBUG':
+ import traceback
+ msger.error(traceback.format_exc())
+ else:
+ msger.error(str(err))
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2007 Red Hat Inc.
+# Copyright (c) 2010, 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+import tempfile
+import glob
+from string import Template
+
+import rpmUtils
+import yum
+
+from mic import msger
+from mic.kickstart import ksparser
+from mic.utils import misc, rpmmisc
+from mic.utils.grabber import TextProgress
+from mic.utils.proxy import get_proxy_for
+from mic.utils.errors import CreatorError
+from mic.utils.safeurl import SafeURL
+
+
+YUMCONF_TEMP = """[main]
+installroot=$installroot
+cachedir=/var/cache/yum
+persistdir=/var/lib/yum
+plugins=0
+reposdir=
+failovermethod=priority
+http_caching=packages
+sslverify=1
+"""
+
+class MyYumRepository(yum.yumRepo.YumRepository):
+ def __init__(self, repoid, nocache):
+ super(MyYumRepository, self).__init__(repoid)
+ self.nocache = nocache
+
+ def __del__(self):
+ pass
+
+ def dirSetup(self):
+ super(MyYumRepository, self).dirSetup()
+ # relocate package dir
+ pkgdir = os.path.join(self.basecachedir, 'packages', self.id)
+ self.setAttribute('_dir_setup_pkgdir', pkgdir)
+ self._dirSetupMkdir_p(self.pkgdir)
+
+ def _getFile(self, url=None,
+ relative=None,
+ local=None,
+ start=None,
+ end=None,
+ copy_local=None,
+ checkfunc=None,
+ text=None,
+ reget='simple',
+ cache=True,
+ size=None):
+
+ m2c_connection = None
+ if not self.sslverify:
+ try:
+ import M2Crypto
+ m2c_connection = M2Crypto.SSL.Connection.clientPostConnectionCheck
+ M2Crypto.SSL.Connection.clientPostConnectionCheck = None
+ except ImportError as err:
+ raise CreatorError("%s, please try to install python-m2crypto" % str(err))
+
+ proxy = None
+ if url:
+ proxy = get_proxy_for(url)
+ else:
+ proxy = get_proxy_for(self.urls[0])
+
+ if proxy:
+ self.proxy = str(proxy)
+
+ size = int(size) if size else None
+ rvalue = super(MyYumRepository, self)._getFile(url,
+ relative,
+ local,
+ start,
+ end,
+ copy_local,
+ checkfunc,
+ text,
+ reget,
+ cache,
+ size)
+
+ if m2c_connection and \
+ not M2Crypto.SSL.Connection.clientPostConnectionCheck:
+ M2Crypto.SSL.Connection.clientPostConnectionCheck = m2c_connection
+
+ return rvalue
+
+from mic.pluginbase import BackendPlugin
+class Yum(BackendPlugin, yum.YumBase):
+ name = 'yum'
+
+ def __init__(self, target_arch, instroot, cachedir, strict_mode = False):
+ yum.YumBase.__init__(self)
+
+ self.cachedir = cachedir
+ self.instroot = instroot
+ self.target_arch = target_arch
+ self.strict_mode = strict_mode
+
+ if self.target_arch:
+ if not rpmUtils.arch.arches.has_key(self.target_arch):
+ rpmUtils.arch.arches["armv7hl"] = "noarch"
+ rpmUtils.arch.arches["armv7tnhl"] = "armv7nhl"
+ rpmUtils.arch.arches["armv7tnhl"] = "armv7thl"
+ rpmUtils.arch.arches["armv7thl"] = "armv7hl"
+ rpmUtils.arch.arches["armv7nhl"] = "armv7hl"
+ self.arch.setup_arch(self.target_arch)
+
+ self.__pkgs_license = {}
+ self.__pkgs_content = {}
+ self.__pkgs_vcsinfo = {}
+ self.check_pkgs = []
+
+ self.install_debuginfo = False
+
+ def doFileLogSetup(self, uid, logfile):
+ # don't do the file log for the livecd as it can lead to open fds
+ # being left and an inability to clean up after ourself
+ pass
+
+ def close(self):
+ try:
+ os.unlink(self.confpath)
+ os.unlink(self.conf.installroot + "/yum.conf")
+ except:
+ pass
+
+ if self.ts:
+ self.ts.close()
+ self._delRepos()
+ self._delSacks()
+ yum.YumBase.close(self)
+ self.closeRpmDB()
+
+ def __del__(self):
+ pass
+
+ def _writeConf(self, confpath, installroot):
+ conf = Template(YUMCONF_TEMP).safe_substitute(installroot=installroot)
+
+ f = file(confpath, "w+")
+ f.write(conf)
+ f.close()
+
+ os.chmod(confpath, 0o644)
+
+ def _cleanupRpmdbLocks(self, installroot):
+ # cleans up temporary files left by bdb so that differing
+ # versions of rpm don't cause problems
+ for f in glob.glob(installroot + "/var/lib/rpm/__db*"):
+ os.unlink(f)
+
+ def setup(self):
+ # create yum.conf
+ (fn, self.confpath) = tempfile.mkstemp(dir=self.cachedir,
+ prefix='yum.conf-')
+ os.close(fn)
+ self._writeConf(self.confpath, self.instroot)
+ self._cleanupRpmdbLocks(self.instroot)
+ # do setup
+ self.doConfigSetup(fn = self.confpath, root = self.instroot)
+ self.conf.cache = 0
+ self.doTsSetup()
+ self.doRpmDBSetup()
+ self.doRepoSetup()
+ self.doSackSetup()
+
+ def preInstall(self, pkg):
+ # FIXME: handle pre-install package
+ return None
+
+ def checkPackage(self, pkg):
+ self.check_pkgs.append(pkg)
+
+ def selectPackage(self, pkg):
+ """Select a given package.
+ Can be specified with name.arch or name*
+ """
+
+ try:
+ self.install(pattern = pkg)
+ return None
+ except yum.Errors.InstallError:
+ return "No package(s) available to install"
+ except yum.Errors.RepoError as e:
+ raise CreatorError("Unable to download from repo : %s" % (e,))
+ except yum.Errors.YumBaseError as e:
+ raise CreatorError("Unable to install: %s" % (e,))
+
+ def deselectPackage(self, pkg):
+ """Deselect package. Can be specified as name.arch or name*
+ """
+
+ sp = pkg.rsplit(".", 2)
+ txmbrs = []
+ if len(sp) == 2:
+ txmbrs = self.tsInfo.matchNaevr(name=sp[0], arch=sp[1])
+
+ if len(txmbrs) == 0:
+ exact, match, unmatch = yum.packages.parsePackages(
+ self.pkgSack.returnPackages(),
+ [pkg],
+ casematch=1)
+ for p in exact + match:
+ txmbrs.append(p)
+
+ if len(txmbrs) > 0:
+ for x in txmbrs:
+ self.tsInfo.remove(x.pkgtup)
+ # we also need to remove from the conditionals
+ # dict so that things don't get pulled back in as a result
+ # of them. yes, this is ugly. conditionals should die.
+ for req, pkgs in self.tsInfo.conditionals.iteritems():
+ if x in pkgs:
+ pkgs.remove(x)
+ self.tsInfo.conditionals[req] = pkgs
+ else:
+ msger.warning("No such package %s to remove" %(pkg,))
+
+ def selectGroup(self, grp, include = ksparser.GROUP_DEFAULT):
+ try:
+ yum.YumBase.selectGroup(self, grp)
+ if include == ksparser.GROUP_REQUIRED:
+ for p in grp.default_packages.keys():
+ self.deselectPackage(p)
+
+ elif include == ksparser.GROUP_ALL:
+ for p in grp.optional_packages.keys():
+ self.selectPackage(p)
+
+ return None
+ except (yum.Errors.InstallError, yum.Errors.GroupsError) as e:
+ return e
+ except yum.Errors.RepoError as e:
+ raise CreatorError("Unable to download from repo : %s" % (e,))
+ except yum.Errors.YumBaseError as e:
+ raise CreatorError("Unable to install: %s" % (e,))
+
+ def addRepository(self, name, url = None, mirrorlist = None, proxy = None,
+ proxy_username = None, proxy_password = None,
+ inc = None, exc = None, ssl_verify=True, nocache=False,
+ cost = None, priority=None):
+ # TODO: Handle priority attribute for repos
+ def _varSubstitute(option):
+ # takes a variable and substitutes like yum configs do
+ option = option.replace("$basearch", rpmUtils.arch.getBaseArch())
+ option = option.replace("$arch", rpmUtils.arch.getCanonArch())
+ return option
+ repo = MyYumRepository(name, nocache)
+
+ # Set proxy
+ repo.proxy = proxy
+ repo.proxy_username = proxy_username
+ repo.proxy_password = proxy_password
+
+ if url:
+ repo.baseurl.append(_varSubstitute(url.full))
+
+ if mirrorlist:
+ repo.mirrorlist = _varSubstitute(mirrorlist)
+
+ conf = yum.config.RepoConf()
+ for k, v in conf.iteritems():
+ if v or not hasattr(repo, k):
+ repo.setAttribute(k, v)
+
+ repo.sslverify = ssl_verify
+
+ repo.basecachedir = self.cachedir
+ repo.base_persistdir = self.conf.persistdir
+ repo.failovermethod = "priority"
+ repo.metadata_expire = 0
+ # Enable gpg check for verifying corrupt packages
+ repo.gpgcheck = 1
+ repo.enable()
+ repo.setup(0)
+ self.repos.add(repo)
+ if cost:
+ repo.cost = cost
+
+ msger.verbose('repo: %s was added' % name)
+ return repo
+
+ def installLocal(self, pkg, po=None, updateonly=False):
+ ts = rpmUtils.transaction.initReadOnlyTransaction()
+ try:
+ hdr = rpmUtils.miscutils.hdrFromPackage(ts, pkg)
+ except rpmUtils.RpmUtilsError as e:
+ raise yum.Errors.MiscError \
+ ('Could not open local rpm file: %s: %s' % (pkg, e))
+
+ self.deselectPackage(hdr['name'])
+ yum.YumBase.installLocal(self, pkg, po, updateonly)
+
+ def installHasFile(self, file):
+ provides_pkg = self.whatProvides(file, None, None)
+ dlpkgs = map(
+ lambda x: x.po,
+ filter(
+ lambda txmbr: txmbr.ts_state in ("i", "u"),
+ self.tsInfo.getMembers()))
+
+ for p in dlpkgs:
+ for q in provides_pkg:
+ if (p == q):
+ return True
+
+ return False
+
+ def runInstall(self, checksize = 0):
+ os.environ["HOME"] = "/"
+ os.environ["LD_PRELOAD"] = ""
+ try:
+ (res, resmsg) = self.buildTransaction()
+ except yum.Errors.RepoError as e:
+ raise CreatorError("Unable to download from repo : %s" %(e,))
+
+ if res != 2:
+ raise CreatorError("Failed to build transaction : %s" \
+ % str.join("\n", resmsg))
+
+ dlpkgs = map(
+ lambda x: x.po,
+ filter(
+ lambda txmbr: txmbr.ts_state in ("i", "u"),
+ self.tsInfo.getMembers()))
+
+ # record all pkg and the content
+ for pkg in dlpkgs:
+ pkg_long_name = misc.RPM_FMT % {
+ 'name': pkg.name,
+ 'arch': pkg.arch,
+ 'version': pkg.version,
+ 'release': pkg.release
+ }
+ self.__pkgs_content[pkg_long_name] = pkg.files
+ license = pkg.license
+ if license in self.__pkgs_license.keys():
+ self.__pkgs_license[license].append(pkg_long_name)
+ else:
+ self.__pkgs_license[license] = [pkg_long_name]
+
+ if pkg.name in self.check_pkgs:
+ self.check_pkgs.remove(pkg.name)
+
+ if self.check_pkgs:
+ raise CreatorError('Packages absent in image: %s' % ','.join(self.check_pkgs))
+
+ total_count = len(dlpkgs)
+ cached_count = 0
+ download_total_size = sum(map(lambda x: int(x.packagesize), dlpkgs))
+
+ msger.info("\nChecking packages cached ...")
+ for po in dlpkgs:
+ local = po.localPkg()
+ repo = filter(lambda r: r.id == po.repoid, self.repos.listEnabled())[0]
+ if repo.nocache and os.path.exists(local):
+ os.unlink(local)
+ if not os.path.exists(local):
+ continue
+ if not self.verifyPkg(local, po, False):
+ msger.warning("Package %s is damaged: %s" \
+ % (os.path.basename(local), local))
+ else:
+ download_total_size -= int(po.packagesize)
+ cached_count += 1
+
+ cache_avail_size = misc.get_filesystem_avail(self.cachedir)
+ if cache_avail_size < download_total_size:
+ raise CreatorError("No enough space used for downloading.")
+
+ # record the total size of installed pkgs
+ pkgs_total_size = 0
+ for x in dlpkgs:
+ if hasattr(x, 'installedsize'):
+ pkgs_total_size += int(x.installedsize)
+ else:
+ pkgs_total_size += int(x.size)
+
+ # check needed size before actually download and install
+ if checksize and pkgs_total_size > checksize:
+ raise CreatorError("No enough space used for installing, "
+ "please resize partition size in ks file")
+
+ msger.info("Packages: %d Total, %d Cached, %d Missed" \
+ % (total_count, cached_count, total_count - cached_count))
+
+ try:
+ repos = self.repos.listEnabled()
+ for repo in repos:
+ repo.setCallback(TextProgress(total_count - cached_count))
+
+ self.downloadPkgs(dlpkgs)
+ # FIXME: sigcheck?
+
+ self.initActionTs()
+ self.populateTs(keepold=0)
+
+ deps = self.ts.check()
+ if len(deps) != 0:
+ # This isn't fatal, Ubuntu has this issue but it is ok.
+ msger.debug(deps)
+ msger.warning("Dependency check failed!")
+
+ rc = self.ts.order()
+ if rc != 0:
+ raise CreatorError("ordering packages for installation failed")
+
+ # FIXME: callback should be refactored a little in yum
+ cb = rpmmisc.RPMInstallCallback(self.ts)
+ cb.tsInfo = self.tsInfo
+ cb.filelog = False
+
+ msger.warning('\nCaution, do NOT interrupt the installation, '
+ 'else mic cannot finish the cleanup.')
+
+ installlogfile = "%s/__catched_stderr.buf" % (self.instroot)
+ msger.enable_logstderr(installlogfile)
+ transactionResult = self.runTransaction(cb)
+ if transactionResult.return_code != 0 and self.strict_mode:
+ raise CreatorError("mic failes to install some packages")
+ self._cleanupRpmdbLocks(self.conf.installroot)
+
+ except rpmUtils.RpmUtilsError as e:
+ raise CreatorError("mic does NOT support delta rpm: %s" % e)
+ except yum.Errors.RepoError as e:
+ raise CreatorError("Unable to download from repo : %s" % e)
+ except yum.Errors.YumBaseError as e:
+ raise CreatorError("Unable to install: %s" % e)
+ finally:
+ msger.disable_logstderr()
+
+ def getVcsInfo(self):
+ if self.__pkgs_vcsinfo:
+ return self.__pkgs_vcsinfo
+ if not self.ts:
+ self.__initialize_transaction()
+ mi = self.ts.dbMatch()
+ for hdr in mi:
+ lname = misc.RPM_FMT % {
+ 'name': hdr['name'],
+ 'arch': hdr['arch'],
+ 'version': hdr['version'],
+ 'release': hdr['release']
+ }
+ try:
+ self.__pkgs_vcsinfo[lname] = hdr['VCS']
+ except ValueError as KeyError:
+ self.__pkgs_vcsinfo[lname] = None
+
+ return self.__pkgs_vcsinfo
+
+ def getAllContent(self):
+ return self.__pkgs_content
+
+ def getPkgsLicense(self):
+ return self.__pkgs_license
+
+ def getFilelist(self, pkgname):
+ if not pkgname:
+ return None
+
+ pkg = filter(lambda txmbr: txmbr.po.name == pkgname, self.tsInfo.getMembers())
+ if not pkg:
+ return None
+ return pkg[0].po.filelist
+
+ def package_url(self, pkgname):
+ pkgs = self.pkgSack.searchNevra(name=pkgname)
+ if pkgs:
+ pkg = pkgs[0]
+
+ repo = pkg.repo
+ url = SafeURL(repo.baseurl[0]).join(pkg.remote_path)
+
+ proxy = repo.proxy
+ if not proxy:
+ proxy = get_proxy_for(url)
+ if proxy:
+ proxies = {str(url.split(':')[0]): str(proxy)}
+ else:
+ proxies = None
+
+ return (url, proxies)
+
+ return (None, None)
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2010, 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+import shutil
+import urlparse
+import rpm
+import glob
+
+import zypp #pylint: disable=import-error
+if not hasattr(zypp, 'PoolQuery') or \
+ not hasattr(zypp.RepoManager, 'loadSolvFile'):
+ raise ImportError("python-zypp in host system cannot support PoolQuery or "
+ "loadSolvFile interface, please update it to enhanced "
+ "version which can be found in download.tizen.org/tools")
+
+from mic import msger
+from mic.kickstart import ksparser
+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.conf import configmgr
+
+class RepositoryStub:
+ def __init__(self):
+ self.name = None
+ self.baseurl = []
+ self.mirrorlist = None
+ self.proxy = None
+ self.proxy_username = None
+ self.proxy_password = None
+ self.nocache = False
+
+ self.enabled = True
+ self.autorefresh = True
+ self.keeppackages = True
+ self.priority = None
+
+from mic.pluginbase import BackendPlugin
+class Zypp(BackendPlugin):
+ name = 'zypp'
+
+ def __init__(self, target_arch, instroot, cachedir, strict_mode = False):
+ self.cachedir = cachedir
+ self.instroot = instroot
+ self.target_arch = target_arch
+ self.strict_mode = strict_mode
+
+ self.__pkgs_license = {}
+ self.__pkgs_content = {}
+ self.__pkgs_vcsinfo = {}
+ self.repos = []
+ self.to_deselect = []
+ self.localpkgs = {}
+ self.repo_manager = None
+ self.repo_manager_options = None
+ self.Z = None
+ self.ts = None
+ self.ts_pre = None
+ self.pkgs_bak = []
+ self.incpkgs = {}
+ self.excpkgs = {}
+ self.pre_pkgs = []
+ self.check_pkgs = []
+ self.probFilterFlags = [ rpm.RPMPROB_FILTER_OLDPACKAGE,
+ rpm.RPMPROB_FILTER_REPLACEPKG ]
+
+ self.has_prov_query = True
+ self.install_debuginfo = False
+ # this can't be changed, it is used by zypp
+ self.tmp_file_path = '/var/tmp'
+
+ def doFileLogSetup(self, uid, logfile):
+ # don't do the file log for the livecd as it can lead to open fds
+ # being left and an inability to clean up after ourself
+ pass
+
+ def closeRpmDB(self):
+ pass
+
+ def close(self):
+ if self.ts:
+ self.ts.closeDB()
+ self.ts = None
+
+ if self.ts_pre:
+ self.ts_pre.closeDB()
+ self.ts_pre = None
+
+ self.pkgs_bak = []
+
+ self.closeRpmDB()
+
+ def __del__(self):
+ self.close()
+
+ def _cleanupRpmdbLocks(self, installroot):
+ # cleans up temporary files left by bdb so that differing
+ # versions of rpm don't cause problems
+ for f in glob.glob(installroot + "/var/lib/rpm/__db*"):
+ os.unlink(f)
+
+ def _cleanupZyppJunk(self, installroot):
+ try:
+ shutil.rmtree(os.path.join(installroot, '.zypp'))
+ except:
+ pass
+
+ def setup(self):
+ self._cleanupRpmdbLocks(self.instroot)
+ # '/var/tmp' is used by zypp to build cache, so make sure
+ # if it exists
+ if not os.path.exists(self.tmp_file_path ):
+ os.makedirs(self.tmp_file_path)
+
+ def whatObsolete(self, pkg):
+ query = zypp.PoolQuery()
+ query.addKind(zypp.ResKind.package)
+ query.addDependency(zypp.SolvAttr.obsoletes, pkg.name(), pkg.edition())
+ query.setMatchExact()
+ for pi in query.queryResults(self.Z.pool()):
+ return pi
+ return None
+
+ def _zyppQueryPackage(self, pkg):
+ query = zypp.PoolQuery()
+ query.addKind(zypp.ResKind.package)
+ query.addAttribute(zypp.SolvAttr.name, pkg)
+ query.setMatchExact()
+ for pi in query.queryResults(self.Z.pool()):
+ return pi
+ return None
+
+ def _splitPkgString(self, pkg):
+ sp = pkg.rsplit(".", 1)
+ name = sp[0]
+ arch = None
+ if len(sp) == 2:
+ arch = sp[1]
+ sysarch = zypp.Arch(self.target_arch)
+ if not zypp.Arch(arch).compatible_with (sysarch):
+ arch = None
+ name = ".".join(sp)
+ return name, arch
+
+ def selectPackage(self, pkg):
+ """Select a given package or package pattern, can be specified
+ with name.arch or name* or *name
+ """
+
+ if not self.Z:
+ self.__initialize_zypp()
+
+ def markPoolItem(obs, pi):
+ if obs == None:
+ pi.status().setToBeInstalled (zypp.ResStatus.USER)
+ else:
+ obs.status().setToBeInstalled (zypp.ResStatus.USER)
+
+ def cmpEVR(p1, p2):
+ # compare criterion: arch compatibility first, then repo
+ # priority, and version last
+ a1 = p1.arch()
+ a2 = p2.arch()
+ if str(a1) != str(a2):
+ if a1.compatible_with(a2):
+ return -1
+ else:
+ return 1
+ # Priority of a repository is an integer value between 0 (the
+ # highest priority) and 99 (the lowest priority)
+ pr1 = int(p1.repoInfo().priority())
+ pr2 = int(p2.repoInfo().priority())
+ if pr1 > pr2:
+ return -1
+ elif pr1 < pr2:
+ return 1
+
+ ed1 = p1.edition()
+ ed2 = p2.edition()
+ (e1, v1, r1) = map(str, [ed1.epoch(), ed1.version(), ed1.release()])
+ (e2, v2, r2) = map(str, [ed2.epoch(), ed2.version(), ed2.release()])
+ return rpm.labelCompare((e1, v1, r1), (e2, v2, r2))
+
+ found = False
+ startx = pkg.startswith("*")
+ endx = pkg.endswith("*")
+ ispattern = startx or endx
+ name, arch = self._splitPkgString(pkg)
+
+ q = zypp.PoolQuery()
+ q.addKind(zypp.ResKind.package)
+
+ if ispattern:
+ if startx and not endx:
+ pattern = '%s$' % (pkg[1:])
+ if endx and not startx:
+ pattern = '^%s' % (pkg[0:-1])
+ if endx and startx:
+ pattern = '%s' % (pkg[1:-1])
+ q.setMatchRegex()
+ q.addAttribute(zypp.SolvAttr.name, pattern)
+
+ elif arch:
+ q.setMatchExact()
+ q.addAttribute(zypp.SolvAttr.name, name)
+
+ else:
+ q.setMatchExact()
+ q.addAttribute(zypp.SolvAttr.name, pkg)
+
+ for pitem in sorted(
+ q.queryResults(self.Z.pool()),
+ cmp=lambda x,y: cmpEVR(zypp.asKindPackage(x), zypp.asKindPackage(y)),
+ reverse=True):
+ item = zypp.asKindPackage(pitem)
+ if item.name() in self.excpkgs.keys() and \
+ self.excpkgs[item.name()] == item.repoInfo().name():
+ continue
+ if item.name() in self.incpkgs.keys() and \
+ self.incpkgs[item.name()] != item.repoInfo().name():
+ continue
+
+ found = True
+ obspkg = self.whatObsolete(item)
+ if arch:
+ if arch == str(item.arch()):
+ pitem.status().setToBeInstalled (zypp.ResStatus.USER)
+ else:
+ markPoolItem(obspkg, pitem)
+ if not ispattern:
+ break
+
+ # Can't match using package name, then search from packge
+ # provides infomation
+ if found == False and not ispattern:
+ q.addAttribute(zypp.SolvAttr.provides, pkg)
+ q.addAttribute(zypp.SolvAttr.name,'')
+
+ for pitem in sorted(
+ q.queryResults(self.Z.pool()),
+ cmp=lambda x,y: cmpEVR(zypp.asKindPackage(x), zypp.asKindPackage(y)),
+ reverse=True):
+ item = zypp.asKindPackage(pitem)
+ if item.name() in self.excpkgs.keys() and \
+ self.excpkgs[item.name()] == item.repoInfo().name():
+ continue
+ if item.name() in self.incpkgs.keys() and \
+ self.incpkgs[item.name()] != item.repoInfo().name():
+ continue
+
+ found = True
+ obspkg = self.whatObsolete(item)
+ markPoolItem(obspkg, pitem)
+ break
+
+ if found:
+ return None
+ else:
+ raise CreatorError("Unable to find package: %s" % (pkg,))
+
+ def inDeselectPackages(self, pitem):
+ """check if specified pacakges are in the list of inDeselectPackages
+ """
+ item = zypp.asKindPackage(pitem)
+ name = item.name()
+ for pkg in self.to_deselect:
+ startx = pkg.startswith("*")
+ endx = pkg.endswith("*")
+ ispattern = startx or endx
+ pkgname, pkgarch = self._splitPkgString(pkg)
+ if not ispattern:
+ if pkgarch:
+ if name == pkgname and str(item.arch()) == pkgarch:
+ return True
+ else:
+ if name == pkgname:
+ return True
+ else:
+ if startx and name.endswith(pkg[1:]):
+ return True
+ if endx and name.startswith(pkg[:-1]):
+ return True
+
+ return False
+
+ def deselectPackage(self, pkg):
+ """collect packages should not be installed"""
+ self.to_deselect.append(pkg)
+
+ def selectGroup(self, grp, include = ksparser.GROUP_DEFAULT):
+ def compareGroup(pitem):
+ item = zypp.asKindPattern(pitem)
+ return item.repoInfo().priority()
+ if not self.Z:
+ self.__initialize_zypp()
+ found = False
+ q = zypp.PoolQuery()
+ q.addKind(zypp.ResKind.pattern)
+ for pitem in sorted(q.queryResults(self.Z.pool()), key=compareGroup):
+ item = zypp.asKindPattern(pitem)
+ summary = "%s" % item.summary()
+ name = "%s" % item.name()
+ if name == grp or summary == grp:
+ found = True
+ pitem.status().setToBeInstalled (zypp.ResStatus.USER)
+ break
+
+ if found:
+ if include == ksparser.GROUP_REQUIRED:
+ map(
+ lambda p: self.deselectPackage(p),
+ grp.default_packages.keys())
+
+ return None
+ else:
+ raise CreatorError("Unable to find pattern: %s" % (grp,))
+
+ def addRepository(self, name,
+ url = None,
+ mirrorlist = None,
+ proxy = None,
+ proxy_username = None,
+ proxy_password = None,
+ inc = None,
+ exc = None,
+ ssl_verify = True,
+ nocache = False,
+ cost=None,
+ priority=None):
+ # TODO: Handle cost attribute for repos
+
+ if not self.repo_manager:
+ self.__initialize_repo_manager()
+
+ if not proxy and url:
+ proxy = get_proxy_for(url)
+
+ repo = RepositoryStub()
+ repo.name = name
+ repo.id = name
+ repo.proxy = proxy
+ repo.proxy_username = proxy_username
+ repo.proxy_password = proxy_password
+ repo.ssl_verify = ssl_verify
+ repo.nocache = nocache
+ repo.baseurl.append(url)
+ if inc:
+ for pkg in inc:
+ self.incpkgs[pkg] = name
+ if exc:
+ for pkg in exc:
+ self.excpkgs[pkg] = name
+
+ if mirrorlist:
+ repo.mirrorlist = mirrorlist
+
+ # Enable gpg check for verifying corrupt packages
+ repo.gpgcheck = 1
+ if priority is not None:
+ # priority 0 has issue in RepoInfo.setPriority
+ repo.priority = priority + 1
+
+ try:
+ repo_info = zypp.RepoInfo()
+ repo_info.setAlias(repo.name)
+ repo_info.setName(repo.name)
+ repo_info.setEnabled(repo.enabled)
+ repo_info.setAutorefresh(repo.autorefresh)
+ repo_info.setKeepPackages(repo.keeppackages)
+ baseurl = zypp.Url(repo.baseurl[0].full)
+ if not ssl_verify:
+ baseurl.setQueryParam("ssl_verify", "no")
+ if proxy:
+ host = urlparse.urlparse(proxy)[1]
+ # scheme, host, path, parm, query, frag = urlparse.urlparse(proxy)
+
+ proxyinfo = host.rsplit(":", 1)
+ host = proxyinfo[0]
+
+ port = "80"
+ if len(proxyinfo) > 1:
+ port = proxyinfo[1]
+
+ if proxy.startswith("socks") and len(proxy.rsplit(':', 1)) == 2:
+ host = proxy.rsplit(':', 1)[0]
+ port = proxy.rsplit(':', 1)[1]
+
+ # parse user/pass from proxy host
+ proxyinfo = host.rsplit("@", 1)
+ if len(proxyinfo) == 2:
+ host = proxyinfo[1]
+ # Known Issue: If password contains ":", which should be
+ # quoted, for example, use '123%3Aabc' instead of 123:abc
+ userpassinfo = proxyinfo[0].rsplit(":", 1)
+ if len(userpassinfo) == 2:
+ proxy_username = userpassinfo[0]
+ proxy_password = userpassinfo[1]
+ elif len(userpassinfo) == 1:
+ proxy_username = userpassinfo[0]
+
+ baseurl.setQueryParam ("proxy", host)
+ baseurl.setQueryParam ("proxyport", port)
+ if proxy_username:
+ baseurl.setQueryParam ("proxyuser", proxy_username)
+ if proxy_password:
+ baseurl.setQueryParam ("proxypass", proxy_password)
+ else:
+ baseurl.setQueryParam ("proxy", "_none_")
+
+ self.repos.append(repo)
+
+ repo_info.addBaseUrl(baseurl)
+
+ if repo.priority is not None:
+ repo_info.setPriority(repo.priority)
+
+ # this hack is used to change zypp credential file location
+ # the default one is $HOME/.zypp, which cause conflicts when
+ # installing some basic packages, and the location doesn't
+ # have any interface actually, so use a tricky way anyway
+ homedir = None
+ if 'HOME' in os.environ:
+ homedir = os.environ['HOME']
+ os.environ['HOME'] = '/'
+ else:
+ os.environ['HOME'] = '/'
+
+ self.repo_manager.addRepository(repo_info)
+
+ # save back the $HOME env
+ if homedir:
+ os.environ['HOME'] = homedir
+ else:
+ del os.environ['HOME']
+
+ self.__build_repo_cache(name)
+
+ except RuntimeError as e:
+ raise CreatorError(str(e))
+
+ msger.verbose('repo: %s was added' % name)
+ return repo
+
+ def installHasFile(self, file):
+ return False
+
+ def preInstall(self, pkg):
+ self.pre_pkgs.append(pkg)
+
+ 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
+ dlpkgs = []
+
+ for pitem in installed_pkgs:
+ if not zypp.isKindPattern(pitem) and \
+ not self.inDeselectPackages(pitem):
+ item = zypp.asKindPackage(pitem)
+ dlpkgs.append(item)
+
+ if item.name() in self.check_pkgs:
+ self.check_pkgs.remove(item.name())
+
+ if not self.install_debuginfo or str(item.arch()) == "noarch":
+ continue
+
+ dipkg = self._zyppQueryPackage("%s-debuginfo" % item.name())
+ if dipkg:
+ ditem = zypp.asKindPackage(dipkg)
+ dlpkgs.append(ditem)
+ else:
+ msger.warning("No debuginfo rpm found for: %s" \
+ % item.name())
+
+ if self.check_pkgs:
+ raise CreatorError('Packages absent in image: %s' % ','.join(self.check_pkgs))
+
+ # record all pkg and the content
+ localpkgs = self.localpkgs.keys()
+ for pkg in dlpkgs:
+ license = ''
+ if pkg.name() in localpkgs:
+ hdr = rpmmisc.readRpmHeader(self.ts, self.localpkgs[pkg.name()])
+ pkg_long_name = misc.RPM_FMT % {
+ 'name': hdr['name'],
+ 'arch': hdr['arch'],
+ 'version': hdr['version'],
+ 'release': hdr['release']
+ }
+ license = hdr['license']
+
+ else:
+ pkg_long_name = misc.RPM_FMT % {
+ 'name': pkg.name(),
+ 'arch': pkg.arch(),
+ 'version': pkg.edition().version(),
+ 'release': pkg.edition().release()
+ }
+
+ license = pkg.license()
+
+ if license in self.__pkgs_license.keys():
+ self.__pkgs_license[license].append(pkg_long_name)
+ else:
+ self.__pkgs_license[license] = [pkg_long_name]
+
+ total_count = len(dlpkgs)
+ cached_count = 0
+ download_total_size = sum(map(lambda x: int(x.downloadSize()), dlpkgs))
+ localpkgs = self.localpkgs.keys()
+
+ msger.info("Checking packages cached ...")
+ for po in dlpkgs:
+ # Check if it is cached locally
+ if po.name() in localpkgs:
+ cached_count += 1
+ else:
+ local = self.getLocalPkgPath(po)
+ name = str(po.repoInfo().name())
+ try:
+ repo = filter(lambda r: r.name == name, self.repos)[0]
+ except IndexError:
+ repo = None
+ nocache = repo.nocache if repo else False
+
+ if os.path.exists(local):
+ if nocache or self.checkPkg(local) !=0:
+ os.unlink(local)
+ else:
+ download_total_size -= int(po.downloadSize())
+ cached_count += 1
+ cache_avail_size = misc.get_filesystem_avail(self.cachedir)
+ if cache_avail_size < download_total_size:
+ raise CreatorError("No enough space used for downloading.")
+
+ # record the total size of installed pkgs
+ install_total_size = sum(map(lambda x: int(x.installSize()), dlpkgs))
+ # check needed size before actually download and install
+
+ # FIXME: for multiple partitions for loop type, check fails
+ # skip the check temporarily
+ #if checksize and install_total_size > checksize:
+ # raise CreatorError("No enough space used for installing, "
+ # "please resize partition size in ks file")
+
+ download_count = total_count - cached_count
+ msger.info("Packages: %d Total, %d Cached, %d Missed" \
+ % (total_count, cached_count, download_count))
+
+ try:
+ if download_count > 0:
+ msger.info("Downloading packages ...")
+ self.downloadPkgs(dlpkgs, download_count)
+ except CreatorError as e:
+ raise CreatorError("Package download failed: %s" %(e,))
+
+ try:
+ self.installPkgs(dlpkgs)
+ except (RepoError, RpmError):
+ raise
+ except Exception as e:
+ raise CreatorError("Package installation failed: %s" % (e,))
+
+ def getVcsInfo(self):
+ if self.__pkgs_vcsinfo:
+ return
+
+ if not self.ts:
+ self.__initialize_transaction()
+
+ mi = self.ts.dbMatch()
+ for hdr in mi:
+ lname = misc.RPM_FMT % {
+ 'name': hdr['name'],
+ 'arch': hdr['arch'],
+ 'version': hdr['version'],
+ 'release': hdr['release']
+ }
+ try:
+ self.__pkgs_vcsinfo[lname] = hdr['VCS']
+ except ValueError:
+ # if rpm not support VCS, set to None
+ self.__pkgs_vcsinfo[lname] = None
+
+ return self.__pkgs_vcsinfo
+
+ def getAllContent(self):
+ if self.__pkgs_content:
+ return self.__pkgs_content
+
+ if not self.ts:
+ self.__initialize_transaction()
+
+ mi = self.ts.dbMatch()
+ for hdr in mi:
+ lname = misc.RPM_FMT % {
+ 'name': hdr['name'],
+ 'arch': hdr['arch'],
+ 'version': hdr['version'],
+ 'release': hdr['release']
+ }
+ self.__pkgs_content[lname] = hdr['FILENAMES']
+
+ return self.__pkgs_content
+
+ def getPkgsLicense(self):
+ return self.__pkgs_license
+
+ def getFilelist(self, pkgname):
+ if not pkgname:
+ return None
+
+ if not self.ts:
+ self.__initialize_transaction()
+
+ mi = self.ts.dbMatch('name', pkgname)
+ for header in mi:
+ return header['FILENAMES']
+
+ def __initialize_repo_manager(self):
+ if self.repo_manager:
+ return
+
+ # Clean up repo metadata
+ shutil.rmtree(self.cachedir + "/etc", ignore_errors = True)
+ shutil.rmtree(self.cachedir + "/solv", ignore_errors = True)
+ shutil.rmtree(self.cachedir + "/raw", ignore_errors = True)
+
+ zypp.KeyRing.setDefaultAccept( zypp.KeyRing.ACCEPT_UNSIGNED_FILE
+ | zypp.KeyRing.ACCEPT_VERIFICATION_FAILED
+ | zypp.KeyRing.ACCEPT_UNKNOWNKEY
+ | zypp.KeyRing.TRUST_KEY_TEMPORARILY
+ )
+
+ self.repo_manager_options = \
+ zypp.RepoManagerOptions(zypp.Pathname(self.instroot))
+
+ self.repo_manager_options.knownReposPath = \
+ zypp.Pathname(self.cachedir + "/etc/zypp/repos.d")
+
+ self.repo_manager_options.repoCachePath = \
+ zypp.Pathname(self.cachedir)
+
+ self.repo_manager_options.repoRawCachePath = \
+ zypp.Pathname(self.cachedir + "/raw")
+
+ self.repo_manager_options.repoSolvCachePath = \
+ zypp.Pathname(self.cachedir + "/solv")
+
+ self.repo_manager_options.repoPackagesCachePath = \
+ zypp.Pathname(self.cachedir + "/packages")
+
+ self.repo_manager = zypp.RepoManager(self.repo_manager_options)
+
+ def __build_repo_cache(self, name):
+ repo = self.repo_manager.getRepositoryInfo(name)
+ if self.repo_manager.isCached(repo) or not repo.enabled():
+ return
+
+ msger.info('Refreshing repository: %s ...' % name)
+ self.repo_manager.buildCache(repo, zypp.RepoManager.BuildIfNeeded)
+
+ def __initialize_zypp(self):
+ if self.Z:
+ return
+
+ zconfig = zypp.ZConfig_instance()
+
+ # Set system architecture
+ if self.target_arch:
+ zconfig.setSystemArchitecture(zypp.Arch(self.target_arch))
+
+ msger.info("zypp architecture is <%s>" % zconfig.systemArchitecture())
+
+ # repoPackagesCachePath is corrected by this
+ self.repo_manager = zypp.RepoManager(self.repo_manager_options)
+ repos = self.repo_manager.knownRepositories()
+ for repo in repos:
+ if not repo.enabled():
+ continue
+ self.repo_manager.loadFromCache(repo)
+
+ self.Z = zypp.ZYppFactory_instance().getZYpp()
+ if configmgr.create['block_recommends']:
+ msger.info("zypp not install recommend packages")
+ self.Z.resolver().setOnlyRequires(True)
+ self.Z.initializeTarget(zypp.Pathname(self.instroot))
+ self.Z.target().load()
+
+ def buildTransaction(self):
+ if not self.Z.resolver().resolvePool():
+ probs = self.Z.resolver().problems()
+
+ for problem in probs:
+ msger.warning("repo problem: %s, %s" \
+ % (problem.description().decode("utf-8"),
+ problem.details().decode("utf-8")))
+
+ raise RepoError("found %d resolver problem, abort!" \
+ % len(probs))
+
+ def getLocalPkgPath(self, po):
+ repoinfo = po.repoInfo()
+ cacheroot = repoinfo.packagesPath()
+ location = po.location()
+ rpmpath = str(location.filename())
+ pkgpath = "%s/%s" % (cacheroot, os.path.basename(rpmpath))
+ return pkgpath
+
+ def installLocal(self, pkg, po=None, updateonly=False):
+ if not self.ts:
+ self.__initialize_transaction()
+
+ solvfile = "%s/.solv" % (self.cachedir)
+
+ rc, out = runner.runtool([fs_related.find_binary_path("rpms2solv"),
+ pkg])
+ if rc == 0:
+ f = open(solvfile, "w+")
+ f.write(out)
+ f.close()
+
+ warnmsg = self.repo_manager.loadSolvFile(solvfile,
+ os.path.basename(pkg))
+ if warnmsg:
+ msger.warning(warnmsg)
+
+ os.unlink(solvfile)
+ else:
+ msger.warning('Can not get %s solv data.' % pkg)
+
+ hdr = rpmmisc.readRpmHeader(self.ts, pkg)
+ arch = zypp.Arch(hdr['arch'])
+ sysarch = zypp.Arch(self.target_arch)
+
+ if arch.compatible_with (sysarch):
+ pkgname = hdr['name']
+ self.localpkgs[pkgname] = pkg
+ self.selectPackage(pkgname)
+ msger.info("Marking %s to be installed" % (pkg))
+
+ else:
+ msger.warning("Cannot add package %s to transaction. "
+ "Not a compatible architecture: %s" \
+ % (pkg, hdr['arch']))
+
+ def downloadPkgs(self, package_objects, count):
+ localpkgs = self.localpkgs.keys()
+ progress_obj = TextProgress(count)
+
+ for po in package_objects:
+ if po.name() in localpkgs:
+ continue
+
+ filename = self.getLocalPkgPath(po)
+ if os.path.exists(filename):
+ if self.checkPkg(filename) == 0:
+ continue
+
+ dirn = os.path.dirname(filename)
+ if not os.path.exists(dirn):
+ os.makedirs(dirn)
+
+ url = self.get_url(po)
+ proxies = self.get_proxies(po)
+
+ try:
+ filename = myurlgrab(url.full, filename, proxies, progress_obj)
+ except CreatorError:
+ self.close()
+ raise
+
+ def preinstallPkgs(self):
+ if not self.ts_pre:
+ self.__initialize_transaction()
+
+ self.ts_pre.order()
+ cb = rpmmisc.RPMInstallCallback(self.ts_pre)
+ cb.headmsg = "Preinstall"
+ installlogfile = "%s/__catched_stderr.buf" % (self.instroot)
+
+ # start to catch stderr output from librpm
+ msger.enable_logstderr(installlogfile)
+
+ errors = self.ts_pre.run(cb.callback, '')
+ # stop catch
+ msger.disable_logstderr()
+ self.ts_pre.closeDB()
+ self.ts_pre = None
+
+ if errors is not None:
+ if len(errors) == 0:
+ msger.warning('scriptlet or other non-fatal errors occurred '
+ 'during transaction.')
+
+ else:
+ for e in errors:
+ msger.warning(e[0])
+ raise RepoError('Could not run transaction.')
+ def show_unresolved_dependencies_msg(self, unresolved_dependencies):
+ for pkg, need, needflags, sense, key in unresolved_dependencies:
+
+ package = '-'.join(pkg)
+
+ if needflags == rpm.RPMSENSE_LESS:
+ deppkg = ' < '.join(need)
+ elif needflags == rpm.RPMSENSE_EQUAL:
+ deppkg = ' = '.join(need)
+ elif needflags == rpm.RPMSENSE_GREATER:
+ deppkg = ' > '.join(need)
+ else:
+ deppkg = '-'.join(need)
+
+ if sense == rpm.RPMDEP_SENSE_REQUIRES:
+ msger.warning("[%s] Requires [%s], which is not provided" \
+ % (package, deppkg))
+
+ elif sense == rpm.RPMDEP_SENSE_CONFLICTS:
+ msger.warning("[%s] Conflicts with [%s]" % (package, deppkg))
+
+ def installPkgs(self, package_objects):
+ if not self.ts:
+ self.__initialize_transaction()
+
+ # clean rpm lock
+ self._cleanupRpmdbLocks(self.instroot)
+ self._cleanupZyppJunk(self.instroot)
+ # Set filters
+ probfilter = 0
+ for flag in self.probFilterFlags:
+ probfilter |= flag
+ self.ts.setProbFilter(probfilter)
+ self.ts_pre.setProbFilter(probfilter)
+
+ localpkgs = self.localpkgs.keys()
+
+ for po in package_objects:
+ pkgname = po.name()
+ if pkgname in localpkgs:
+ rpmpath = self.localpkgs[pkgname]
+ else:
+ rpmpath = self.getLocalPkgPath(po)
+
+ if not os.path.exists(rpmpath):
+ # Maybe it is a local repo
+ rpmuri = self.get_url(po)
+ if rpmuri.startswith("file:/"):
+ rpmpath = rpmuri[5:]
+
+ if not os.path.exists(rpmpath):
+ raise RpmError("Error: %s doesn't exist" % rpmpath)
+
+ h = rpmmisc.readRpmHeader(self.ts, rpmpath)
+
+ if pkgname in self.pre_pkgs:
+ msger.verbose("pre-install package added: %s" % pkgname)
+ self.ts_pre.addInstall(h, rpmpath, 'u')
+
+ #for rpm4.14 vesion, need to split addInstall for these two transactionSet.
+ #addInstall for self.ts should be after self.ts_pre done.
+ self.pkgs_bak.append({"header": h, "rpmpath": rpmpath})
+
+ unresolved_dependencies = self.ts.check()
+ if not unresolved_dependencies:
+ if self.pre_pkgs:
+ self.preinstallPkgs()
+
+ for pkg_bak in self.pkgs_bak:
+ self.ts.addInstall(pkg_bak["header"], pkg_bak["rpmpath"], 'u')
+ self.ts.order()
+ cb = rpmmisc.RPMInstallCallback(self.ts)
+ installlogfile = "%s/__catched_stderr.buf" % (self.instroot)
+
+ # start to catch stderr output from librpm
+ msger.enable_logstderr(installlogfile)
+
+ errors = self.ts.run(cb.callback, '')
+ # stop catch
+ msger.disable_logstderr()
+ self.ts.closeDB()
+ self.ts = None
+ self.pkgs_bak = []
+
+ if errors is not None:
+ if len(errors) == 0:
+ msger.warning('scriptlet or other non-fatal errors occurred '
+ 'during transaction.')
+ if self.strict_mode:
+ raise CreatorError("mic failes to install some packages")
+ else:
+ for e in errors:
+ msger.warning(e[0])
+ raise RepoError('Could not run transaction.')
+
+ else:
+ self.show_unresolved_dependencies_msg(unresolved_dependencies)
+ raise RepoError("Unresolved dependencies, transaction failed.")
+
+ def __initialize_transaction(self):
+ if not self.ts:
+ self.ts = rpm.TransactionSet(self.instroot)
+ # Set to not verify DSA signatures.
+ self.ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES|rpm._RPMVSF_NODIGESTS)
+
+ if not self.ts_pre:
+ self.ts_pre = rpm.TransactionSet(self.instroot)
+ # Just unpack the files, don't run scripts
+ self.ts_pre.setFlags(rpm.RPMTRANS_FLAG_ALLFILES | rpm.RPMTRANS_FLAG_NOSCRIPTS)
+ # Set to not verify DSA signatures.
+ self.ts_pre.setVSFlags(rpm._RPMVSF_NOSIGNATURES|rpm._RPMVSF_NODIGESTS)
+
+ def checkPkg(self, pkg):
+ ret = 1
+ if not os.path.exists(pkg):
+ return ret
+ ret = rpmmisc.checkRpmIntegrity('rpm', pkg)
+ if ret != 0:
+ msger.warning("package %s is damaged: %s" \
+ % (os.path.basename(pkg), pkg))
+
+ return ret
+
+ def _add_prob_flags(self, *flags):
+ for flag in flags:
+ if flag not in self.probFilterFlags:
+ self.probFilterFlags.append(flag)
+
+ def get_proxies(self, pobj):
+ if not pobj:
+ return None
+
+ proxy = None
+ proxies = None
+ repoinfo = pobj.repoInfo()
+ reponame = "%s" % repoinfo.name()
+ repos = filter(lambda r: r.name == reponame, self.repos)
+ repourl = str(repoinfo.baseUrls()[0])
+
+ if repos:
+ proxy = repos[0].proxy
+ if not proxy:
+ proxy = get_proxy_for(repourl)
+ if proxy:
+ proxies = {str(repourl.split(':')[0]): str(proxy)}
+
+ return proxies
+
+ def get_url(self, pobj):
+ if not pobj:
+ return None
+
+ name = str(pobj.repoInfo().name())
+ try:
+ repo = filter(lambda r: r.name == name, self.repos)[0]
+ except IndexError:
+ return None
+
+ location = pobj.location()
+ location = str(location.filename())
+ if location.startswith("./"):
+ location = location[2:]
+
+ return repo.baseurl[0].join(location)
+
+ def package_url(self, pkgname):
+
+ def cmpEVR(p1, p2):
+ ed1 = p1.edition()
+ ed2 = p2.edition()
+ (e1, v1, r1) = map(str, [ed1.epoch(), ed1.version(), ed1.release()])
+ (e2, v2, r2) = map(str, [ed2.epoch(), ed2.version(), ed2.release()])
+ return rpm.labelCompare((e1, v1, r1), (e2, v2, r2))
+
+ if not self.Z:
+ self.__initialize_zypp()
+
+ q = zypp.PoolQuery()
+ q.addKind(zypp.ResKind.package)
+ q.setMatchExact()
+ q.addAttribute(zypp.SolvAttr.name, pkgname)
+ items = sorted(q.queryResults(self.Z.pool()),
+ cmp=lambda x,y: cmpEVR(zypp.asKindPackage(x), zypp.asKindPackage(y)),
+ reverse=True)
+
+ if items:
+ item = zypp.asKindPackage(items[0])
+ url = self.get_url(item)
+ proxies = self.get_proxies(item)
+ return (url, proxies)
+
+ return (None, None)
--- /dev/null
+#! /usr/bin/python2
+#
+# Copyright (c) 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import subprocess
+from mic import chroot, msger, rt_util
+from mic.utils import misc, errors, fs_related, runner
+from mic.imager import fs
+from mic.plugin import pluginmgr
+
+from mic.pluginbase import ImagerPlugin
+class FsPlugin(ImagerPlugin):
+ name = 'fs'
+
+ @classmethod
+ def do_create(self, args):
+ """${cmd_name}: create fs image
+
+ """
+ creatoropts, pkgmgr, recording_pkgs = rt_util.prepare_create(args)
+
+ creator = fs.FsImageCreator(creatoropts, pkgmgr)
+ creator._include_src = args.include_src
+
+ if len(recording_pkgs) > 0:
+ creator._recording_pkgs = recording_pkgs
+
+ self.check_image_exists(creator.destdir,
+ creator.pack_to,
+ [creator.name],
+ creatoropts['release'])
+
+ try:
+ creator.check_depend_tools()
+ creator.mount(None, creatoropts["cachedir"])
+ creator.install()
+ creator.tpkinstall()
+ #Download the source packages ###private options
+ if args.include_src:
+ installed_pkgs = creator.get_installed_packages()
+ msger.info('Generating the image with source rpms included ...')
+ if not misc.SrcpkgsDownload(installed_pkgs, creatoropts["repomd"],
+ creator._instroot, creatoropts["cachedir"]):
+ msger.warning("Source packages can't be downloaded")
+
+ creator.configure(creatoropts["repomd"])
+ creator.copy_kernel()
+ creator.unmount()
+ creator.package(creatoropts["destdir"])
+ creator.create_manifest()
+ if creatoropts['release'] is not None:
+ creator.release_output(args.ksfile, creatoropts['destdir'],
+ creatoropts['release'])
+ creator.print_outimage_info()
+ except errors.CreatorError:
+ raise
+ 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 as err:
+ msger.warning(str(err))
+
+
+ msger.info("Finished.")
+ return 0
+
+ @classmethod
+ def do_chroot(self, target, cmd=[]):#chroot.py parse opts&args
+ try:
+ if len(cmd) != 0:
+ cmdline = ' '.join(cmd)
+ else:
+ cmdline = "/bin/bash"
+ envcmd = fs_related.find_binary_inchroot("env", target)
+ if envcmd:
+ cmdline = "%s HOME=/root %s" % (envcmd, cmdline)
+ chroot.chroot(target, None, cmdline)
+ finally:
+ chroot.cleanup_after_chroot("dir", None, None, None)
+ return 1
--- /dev/null
+#! /usr/bin/python2
+#
+# Copyright (c) 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+import subprocess
+import shutil
+import tempfile
+
+from mic import chroot, msger, rt_util
+from mic.utils import misc, fs_related, errors, runner
+from mic.plugin import pluginmgr
+from mic.imager.loop import LoopImageCreator, load_mountpoints
+
+from mic.pluginbase import ImagerPlugin
+class LoopPlugin(ImagerPlugin):
+ name = 'loop'
+
+ @classmethod
+ def do_create(self, args):
+ """${cmd_name}: create loop image
+ """
+
+ creatoropts, pkgmgr, recording_pkgs = rt_util.prepare_create(args)
+
+ creator = LoopImageCreator(creatoropts,
+ pkgmgr,
+ args.compress_image,
+ args.shrink)
+
+ if len(recording_pkgs) > 0:
+ creator._recording_pkgs = recording_pkgs
+
+ image_names = [creator.name + ".img"]
+ image_names.extend(creator.get_image_names())
+ self.check_image_exists(creator.destdir,
+ creator.pack_to,
+ image_names,
+ creatoropts['release'])
+
+ try:
+ creator.check_depend_tools()
+ creator.mount(None, creatoropts["cachedir"])
+ creator.install()
+ creator.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()
+
+ if creatoropts['release'] is not None:
+ creator.release_output(args.ksfile,
+ creatoropts['destdir'],
+ creatoropts['release'])
+ creator.print_outimage_info()
+
+ except errors.CreatorError:
+ raise
+ 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 as err:
+ msger.warning(str(err))
+
+ msger.info("Finished.")
+ return 0
+
+ @classmethod
+ def _do_chroot_tar(cls, target, cmd=[]):
+ mountfp_xml = os.path.splitext(target)[0] + '.xml'
+ if not os.path.exists(mountfp_xml):
+ raise errors.CreatorError("No mount point file found for this tar "
+ "image, please check %s" % mountfp_xml)
+
+ import tarfile
+ tar = tarfile.open(target, 'r')
+ tmpdir = misc.mkdtemp()
+ tar.extractall(path=tmpdir)
+ tar.close()
+
+ mntdir = misc.mkdtemp()
+
+ loops = []
+ for (mp, label, name, size, fstype) in load_mountpoints(mountfp_xml):
+ if fstype in ("ext2", "ext3", "ext4"):
+ myDiskMount = fs_related.ExtDiskMount
+ elif fstype == "btrfs":
+ myDiskMount = fs_related.BtrfsDiskMount
+ elif fstype in ("vfat", "msdos"):
+ myDiskMount = fs_related.VfatDiskMount
+ else:
+ raise errors.CreatorError("Cannot support fstype: %s" % fstype)
+
+ name = os.path.join(tmpdir, name)
+ size = size * 1024 * 1024
+ loop = myDiskMount(fs_related.SparseLoopbackDisk(name, size),
+ os.path.join(mntdir, mp.lstrip('/')),
+ fstype, size, label)
+
+ try:
+ msger.verbose("Mount %s to %s" % (mp, mntdir + mp))
+ fs_related.makedirs(os.path.join(mntdir, mp.lstrip('/')))
+ loop.mount()
+
+ except:
+ loop.cleanup()
+ for lp in reversed(loops):
+ chroot.cleanup_after_chroot("img", lp, None, mntdir)
+
+ shutil.rmtree(tmpdir, ignore_errors=True)
+ raise
+
+ loops.append(loop)
+
+ try:
+ if len(cmd) != 0:
+ cmdline = "/usr/bin/env HOME=/root " + ' '.join(cmd)
+ else:
+ cmdline = "/usr/bin/env HOME=/root /bin/bash"
+ chroot.chroot(mntdir, None, cmdline)
+ except:
+ raise errors.CreatorError("Failed to chroot to %s." % target)
+ finally:
+ for loop in reversed(loops):
+ chroot.cleanup_after_chroot("img", loop, None, mntdir)
+
+ shutil.rmtree(tmpdir, ignore_errors=True)
+
+ @classmethod
+ def do_chroot(cls, target, cmd=[]):
+ if target.endswith('.tar'):
+ import tarfile
+ if tarfile.is_tarfile(target):
+ LoopPlugin._do_chroot_tar(target, cmd)
+ return
+ else:
+ raise errors.CreatorError("damaged tarball for loop images")
+
+ img = target
+ imgsize = misc.get_file_size(img) * 1024 * 1024
+ imgtype = misc.get_image_type(img)
+ if imgtype == "btrfsimg":
+ fstype = "btrfs"
+ myDiskMount = fs_related.BtrfsDiskMount
+ elif imgtype in ("ext3fsimg", "ext4fsimg"):
+ fstype = imgtype[:4]
+ myDiskMount = fs_related.ExtDiskMount
+ elif imgtype == "f2fsimg":
+ fstype = "f2fs"
+ myDiskMount = fs_related.F2fsDiskMount
+ else:
+ raise errors.CreatorError("Unsupported filesystem type: %s" \
+ % imgtype)
+
+ extmnt = misc.mkdtemp()
+ extloop = myDiskMount(fs_related.SparseLoopbackDisk(img, imgsize),
+ extmnt,
+ fstype,
+ 4096,
+ "%s label" % fstype)
+ try:
+ extloop.mount()
+
+ except errors.MountError:
+ extloop.cleanup()
+ shutil.rmtree(extmnt, ignore_errors=True)
+ raise
+
+ try:
+ if cmd is not None:
+ cmdline = cmd
+ else:
+ cmdline = "/bin/bash"
+ envcmd = fs_related.find_binary_inchroot("env", extmnt)
+ if envcmd:
+ cmdline = "%s HOME=/root %s" % (envcmd, cmdline)
+ chroot.chroot(extmnt, None, cmdline)
+ except:
+ raise errors.CreatorError("Failed to chroot to %s." % img)
+ finally:
+ chroot.cleanup_after_chroot("img", extloop, None, extmnt)
+
+ @classmethod
+ def do_unpack(cls, srcimg):
+ image = os.path.join(tempfile.mkdtemp(dir="/var/tmp", prefix="tmp"),
+ "target.img")
+ msger.info("Copying file system ...")
+ shutil.copyfile(srcimg, image)
+ return image
--- /dev/null
+#
+# Copyright (c) 2014 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+import subprocess
+import shutil
+
+from mic import msger, rt_util
+from mic.plugin import pluginmgr
+from mic.pluginbase import ImagerPlugin
+from mic.imager.qcow import QcowImageCreator
+from mic.utils import errors, runner
+
+class QcowPlugin(ImagerPlugin):
+ name = 'qcow'
+
+ @classmethod
+ def do_create(cls, args):
+ """${cmd_name}: create qcow image
+ """
+
+ creatoropts, pkgmgr, recording_pkgs = rt_util.prepare_create(args)
+
+ creator = QcowImageCreator(creatoropts,
+ pkgmgr)
+
+ if len(recording_pkgs) > 0:
+ creator._recording_pkgs = recording_pkgs
+
+ image_names = [creator.name + ".img"]
+ image_names.extend(creator.get_image_names())
+ cls.check_image_exists(creator.destdir,
+ creator.pack_to,
+ image_names,
+ creatoropts['release'])
+
+ try:
+ creator.check_depend_tools()
+ creator.mount(None, creatoropts["cachedir"])
+ creator.install()
+ creator.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()
+
+ if creatoropts['release'] is not None:
+ creator.release_output(args.ksfile,
+ creatoropts['destdir'],
+ creatoropts['release'])
+ creator.print_outimage_info()
+
+ except errors.CreatorError:
+ raise
+ 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 as err:
+ msger.warning(str(err))
+
+
+ msger.info("Finished.")
+ return 0
+
+ @classmethod
+ def do_chroot(cls, target, cmd=[]):
+ pass
+
+ @classmethod
+ def do_unpack(cls, srcimg):
+ pass
--- /dev/null
+#! /usr/bin/python2
+#
+# Copyright (c) 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+import subprocess
+import shutil
+import re
+import tempfile
+
+from mic import chroot, msger, rt_util
+from mic.utils import misc, fs_related, errors, runner
+from mic.plugin import pluginmgr
+from mic.utils.partitionedfs import PartitionedMount
+
+import mic.imager.raw as raw
+
+from mic.pluginbase import ImagerPlugin
+class RawPlugin(ImagerPlugin):
+ name = 'raw'
+
+ @classmethod
+ def do_create(self, args):
+ """${cmd_name}: create raw image
+ """
+
+ creatoropts, pkgmgr, recording_pkgs = rt_util.prepare_create(args)
+
+ creator = raw.RawImageCreator(creatoropts, pkgmgr, args.compress_image,
+ args.generate_bmap, args.fstab_entry)
+
+ if len(recording_pkgs) > 0:
+ creator._recording_pkgs = recording_pkgs
+
+ images = ["%s-%s.raw" % (creator.name, disk_name)
+ for disk_name in creator.get_disk_names()]
+ self.check_image_exists(creator.destdir,
+ creator.pack_to,
+ images,
+ creatoropts['release'])
+
+ try:
+ creator.check_depend_tools()
+ creator.mount(None, creatoropts["cachedir"])
+ creator.install()
+ creator.tpkinstall()
+ creator.configure(creatoropts["repomd"])
+ creator.copy_kernel()
+ creator.unmount()
+ creator.generate_bmap()
+ creator.package(creatoropts["destdir"])
+ creator.create_manifest()
+ if creatoropts['release'] is not None:
+ creator.release_output(args.ksfile, creatoropts['destdir'], creatoropts['release'])
+ creator.print_outimage_info()
+
+ except errors.CreatorError:
+ raise
+ 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 as err:
+ msger.warning(str(err))
+
+
+ msger.info("Finished.")
+ return 0
+
+ @classmethod
+ def do_chroot(cls, target, cmd=[]):
+ img = target
+ imgsize = misc.get_file_size(img) * 1024 * 1024
+ partedcmd = fs_related.find_binary_path("parted")
+ disk = fs_related.SparseLoopbackDisk(img, imgsize)
+ imgmnt = misc.mkdtemp()
+ imgloop = PartitionedMount(imgmnt, skipformat = True)
+ imgloop.add_disk('/dev/sdb', disk)
+ img_fstype = "ext3"
+
+ msger.info("Partition Table:")
+ partnum = []
+ for line in runner.outs([partedcmd, "-s", img, "print"]).splitlines():
+ # no use strip to keep line output here
+ if "Number" in line:
+ msger.raw(line)
+ if line.strip() and line.strip()[0].isdigit():
+ partnum.append(line.strip()[0])
+ msger.raw(line)
+
+ rootpart = None
+ if len(partnum) > 1:
+ rootpart = msger.choice("please choose root partition", partnum)
+
+ # Check the partitions from raw disk.
+ # if choose root part, the mark it as mounted
+ if rootpart:
+ root_mounted = True
+ else:
+ root_mounted = False
+ partition_mounts = 0
+ for line in runner.outs([ partedcmd, "-s", img, "unit", "B", "print" ]).splitlines():
+ line = line.strip()
+
+ # Lines that start with number are the partitions,
+ # because parted can be translated we can't refer to any text lines.
+ if not line or not line[0].isdigit():
+ continue
+
+ # Some vars have extra , as list seperator.
+ line = line.replace(",","")
+
+ # Example of parted output lines that are handled:
+ # Number Start End Size Type File system Flags
+ # 1 512B 3400000511B 3400000000B primary
+ # 2 3400531968B 3656384511B 255852544B primary linux-swap(v1)
+ # 3 3656384512B 3720347647B 63963136B primary fat16 boot, lba
+
+ partition_info = re.split("\s+", line)
+
+ size = partition_info[3].split("B")[0]
+
+ if len(partition_info) < 6 or partition_info[5] in ["boot"]:
+ # No filesystem can be found from partition line. Assuming
+ # btrfs, because that is the only MeeGo fs that parted does
+ # not recognize properly.
+ # TODO: Can we make better assumption?
+ fstype = "btrfs"
+ elif partition_info[5] in [ "ext2", "ext3", "ext4", "btrfs", "f2fs" ]:
+ fstype = partition_info[5]
+ elif partition_info[5] in [ "fat16", "fat32" ]:
+ fstype = "vfat"
+ elif "swap" in partition_info[5]:
+ fstype = "swap"
+ else:
+ raise errors.CreatorError("Could not recognize partition fs type '%s'." %
+ partition_info[5])
+
+ if rootpart and rootpart == line[0]:
+ mountpoint = '/'
+ elif not root_mounted and fstype in [ "ext2", "ext3", "ext4", "btrfs", "f2fs" ]:
+ # TODO: Check that this is actually the valid root partition from /etc/fstab
+ mountpoint = "/"
+ root_mounted = True
+ elif fstype == "swap":
+ mountpoint = "swap"
+ else:
+ # TODO: Assing better mount points for the rest of the partitions.
+ partition_mounts += 1
+ mountpoint = "/media/partition_%d" % partition_mounts
+
+ if "boot" in partition_info:
+ boot = True
+ else:
+ boot = False
+
+ msger.verbose("Size: %s Bytes, fstype: %s, mountpoint: %s, boot: %s" %
+ (size, fstype, mountpoint, boot))
+ # TODO: add_partition should take bytes as size parameter.
+ imgloop.add_partition((int)(size)/1024/1024, "/dev/sdb", mountpoint,
+ fstype = fstype, boot = boot)
+
+ try:
+ imgloop.mount()
+
+ except errors.MountError:
+ imgloop.cleanup()
+ raise
+
+ try:
+ if len(cmd) != 0:
+ cmdline = ' '.join(cmd)
+ else:
+ cmdline = "/bin/bash"
+ envcmd = fs_related.find_binary_inchroot("env", imgmnt)
+ if envcmd:
+ cmdline = "%s HOME=/root %s" % (envcmd, cmdline)
+ chroot.chroot(imgmnt, None, cmdline)
+ except:
+ raise errors.CreatorError("Failed to chroot to %s." %img)
+ finally:
+ chroot.cleanup_after_chroot("img", imgloop, None, imgmnt)
+
+ @classmethod
+ def do_unpack(cls, srcimg):
+ srcimgsize = (misc.get_file_size(srcimg)) * 1024 * 1024
+ srcmnt = misc.mkdtemp("srcmnt")
+ disk = fs_related.SparseLoopbackDisk(srcimg, srcimgsize)
+ srcloop = PartitionedMount(srcmnt, skipformat = True)
+
+ srcloop.add_disk('/dev/sdb', disk)
+ srcloop.add_partition(srcimgsize/1024/1024, "/dev/sdb", "/", "ext3", boot=False)
+ try:
+ srcloop.mount()
+
+ except errors.MountError:
+ srcloop.cleanup()
+ raise
+
+ image = os.path.join(tempfile.mkdtemp(dir = "/var/tmp", prefix = "tmp"), "target.img")
+ args = ['dd', "if=%s" % srcloop.partitions[0]['device'], "of=%s" % image]
+
+ msger.info("`dd` image ...")
+ rc = runner.show(args)
+ srcloop.cleanup()
+ shutil.rmtree(os.path.dirname(srcmnt), ignore_errors = True)
+
+ if rc != 0:
+ raise errors.CreatorError("Failed to dd")
+ else:
+ return image
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2006, 2007, 2008 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+"""
+Base classes for creating commands and syntax version object.
+
+This module exports several important base classes:
+
+ BaseData - The base abstract class for all data objects. Data objects
+ are contained within a BaseHandler object.
+
+ BaseHandler - The base abstract class from which versioned kickstart
+ handler are derived. Subclasses of BaseHandler hold
+ BaseData and KickstartCommand objects.
+
+ DeprecatedCommand - An abstract subclass of KickstartCommand that should
+ be further subclassed by users of this module. When
+ a subclass is used, a warning message will be
+ printed.
+
+ KickstartCommand - The base abstract class for all kickstart commands.
+ Command objects are contained within a BaseHandler
+ object.
+"""
+import gettext
+gettext.textdomain("pykickstart")
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+import types
+import warnings
+from pykickstart.errors import *
+from pykickstart.ko import *
+from pykickstart.parser import Packages,TpkPackages
+from pykickstart.version import versionToString
+
+###
+### COMMANDS
+###
+class KickstartCommand(KickstartObject):
+ """The base class for all kickstart commands. This is an abstract class."""
+ removedKeywords = []
+ removedAttrs = []
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ """Create a new KickstartCommand instance. This method must be
+ provided by all subclasses, but subclasses must call
+ KickstartCommand.__init__ first. Instance attributes:
+
+ currentCmd -- The name of the command in the input file that
+ caused this handler to be run.
+ currentLine -- The current unprocessed line from the input file
+ that caused this handler to be run.
+ handler -- A reference to the BaseHandler subclass this
+ command is contained withing. This is needed to
+ allow referencing of Data objects.
+ lineno -- The current line number in the input file.
+ writePriority -- An integer specifying when this command should be
+ printed when iterating over all commands' __str__
+ methods. The higher the number, the later this
+ command will be written. All commands with the
+ same priority will be written alphabetically.
+ """
+
+ # We don't want people using this class by itself.
+ if self.__class__ is KickstartCommand:
+ raise TypeError ("KickstartCommand is an abstract class.")
+
+ KickstartObject.__init__(self, *args, **kwargs)
+
+ self.writePriority = writePriority
+
+ # These will be set by the dispatcher.
+ self.currentCmd = ""
+ self.currentLine = ""
+ self.handler = None
+ self.lineno = 0
+
+ # If a subclass provides a removedKeywords list, remove all the
+ # members from the kwargs list before we start processing it. This
+ # ensures that subclasses don't continue to recognize arguments that
+ # were removed.
+ for arg in filter(kwargs.has_key, self.removedKeywords):
+ kwargs.pop(arg)
+
+ def __call__(self, *args, **kwargs):
+ """Set multiple attributes on a subclass of KickstartCommand at once
+ via keyword arguments. Valid attributes are anything specified in
+ a subclass, but unknown attributes will be ignored.
+ """
+ for (key, val) in kwargs.items():
+ # Ignore setting attributes that were removed in a subclass, as
+ # if they were unknown attributes.
+ if key in self.removedAttrs:
+ continue
+
+ if hasattr(self, key):
+ setattr(self, key, val)
+
+ def __str__(self):
+ """Return a string formatted for output to a kickstart file. This
+ method must be provided by all subclasses.
+ """
+ return KickstartObject.__str__(self)
+
+ def parse(self, args):
+ """Parse the list of args and set data on the KickstartCommand object.
+ This method must be provided by all subclasses.
+ """
+ raise TypeError ("parse() not implemented for KickstartCommand")
+
+ def apply(self, instroot="/"):
+ """Write out the configuration related to the KickstartCommand object.
+ Subclasses which do not provide this method will not have their
+ configuration written out.
+ """
+ return
+
+ def dataList(self):
+ """For commands that can occur multiple times in a single kickstart
+ file (like network, part, etc.), return the list that we should
+ append more data objects to.
+ """
+ return None
+
+ def deleteRemovedAttrs(self):
+ """Remove all attributes from self that are given in the removedAttrs
+ list. This method should be called from __init__ in a subclass,
+ but only after the superclass's __init__ method has been called.
+ """
+ for attr in filter(lambda k: hasattr(self, k), self.removedAttrs):
+ delattr(self, attr)
+
+ # Set the contents of the opts object (an instance of optparse.Values
+ # returned by parse_args) as attributes on the KickstartCommand object.
+ # It's useful to call this from KickstartCommand subclasses after parsing
+ # the arguments.
+ def _setToSelf(self, optParser, opts):
+ self._setToObj(optParser, opts, self)
+
+ # Sets the contents of the opts object (an instance of optparse.Values
+ # returned by parse_args) as attributes on the provided object obj. It's
+ # useful to call this from KickstartCommand subclasses that handle lists
+ # of objects (like partitions, network devices, etc.) and need to populate
+ # a Data object.
+ def _setToObj(self, optParser, opts, obj):
+ for key in filter (lambda k: getattr(opts, k) != None, optParser.keys()):
+ setattr(obj, key, getattr(opts, key))
+
+class DeprecatedCommand(KickstartCommand):
+ """Specify that a command is deprecated and no longer has any function.
+ Any command that is deprecated should be subclassed from this class,
+ only specifying an __init__ method that calls the superclass's __init__.
+ This is an abstract class.
+ """
+ def __init__(self, writePriority=None, *args, **kwargs):
+ # We don't want people using this class by itself.
+ if self.__class__ is KickstartCommand:
+ raise TypeError ("DeprecatedCommand is an abstract class.")
+
+ # Create a new DeprecatedCommand instance.
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+
+ def __str__(self):
+ """Placeholder since DeprecatedCommands don't work anymore."""
+ return ""
+
+ def parse(self, args):
+ """Print a warning message if the command is seen in the input file."""
+ mapping = {"lineno": self.lineno, "cmd": self.currentCmd}
+ warnings.warn(_("Ignoring deprecated command on line %(lineno)s: The %(cmd)s command has been deprecated and no longer has any effect. It may be removed from future releases, which will result in a fatal error from kickstart. Please modify your kickstart file to remove this command.") % mapping, DeprecationWarning)
+
+
+###
+### HANDLERS
+###
+class BaseHandler(KickstartObject):
+ """Each version of kickstart syntax is provided by a subclass of this
+ class. These subclasses are what users will interact with for parsing,
+ extracting data, and writing out kickstart files. This is an abstract
+ class.
+
+ version -- The version this syntax handler supports. This is set by
+ a class attribute of a BaseHandler subclass and is used to
+ set up the command dict. It is for read-only use.
+ """
+ version = None
+
+ def __init__(self, mapping=None, dataMapping=None, commandUpdates=None,
+ dataUpdates=None, *args, **kwargs):
+ """Create a new BaseHandler instance. This method must be provided by
+ all subclasses, but subclasses must call BaseHandler.__init__ first.
+
+ mapping -- A custom map from command strings to classes,
+ useful when creating your own handler with
+ special command objects. It is otherwise unused
+ and rarely needed. If you give this argument,
+ the mapping takes the place of the default one
+ and so must include all commands you want
+ recognized.
+ dataMapping -- This is the same as mapping, but for data
+ objects. All the same comments apply.
+ commandUpdates -- This is similar to mapping, but does not take
+ the place of the defaults entirely. Instead,
+ this mapping is applied after the defaults and
+ updates it with just the commands you want to
+ modify.
+ dataUpdates -- This is the same as commandUpdates, but for
+ data objects.
+
+
+ Instance attributes:
+
+ commands -- A mapping from a string command to a KickstartCommand
+ subclass object that handles it. Multiple strings can
+ map to the same object, but only one instance of the
+ command object should ever exist. Most users should
+ never have to deal with this directly, as it is
+ manipulated internally and called through dispatcher.
+ currentLine -- The current unprocessed line from the input file
+ that caused this handler to be run.
+ packages -- An instance of pykickstart.parser.Packages which
+ describes the packages section of the input file.
+ platform -- A string describing the hardware platform, which is
+ needed only by system-config-kickstart.
+ scripts -- A list of pykickstart.parser.Script instances, which is
+ populated by KickstartParser.addScript and describes the
+ %pre/%post/%traceback script section of the input file.
+ """
+
+ # We don't want people using this class by itself.
+ if self.__class__ is BaseHandler:
+ raise TypeError ("BaseHandler is an abstract class.")
+
+ KickstartObject.__init__(self, *args, **kwargs)
+
+ # This isn't really a good place for these, but it's better than
+ # everything else I can think of.
+ self.scripts = []
+ self.packages = Packages()
+ self.tpk_packages = TpkPackages()
+ self.platform = ""
+
+ # These will be set by the dispatcher.
+ self.commands = {}
+ self.currentLine = 0
+
+ # A dict keyed by an integer priority number, with each value being a
+ # list of KickstartCommand subclasses. This dict is maintained by
+ # registerCommand and used in __str__. No one else should be touching
+ # it.
+ self._writeOrder = {}
+
+ self._registerCommands(mapping, dataMapping, commandUpdates, dataUpdates)
+
+ def __str__(self):
+ """Return a string formatted for output to a kickstart file."""
+ retval = ""
+
+ if self.platform != "":
+ retval += "#platform=%s\n" % self.platform
+
+ retval += "#version=%s\n" % versionToString(self.version)
+
+ lst = self._writeOrder.keys()
+ lst.sort()
+
+ for prio in lst:
+ for obj in self._writeOrder[prio]:
+ retval += obj.__str__()
+
+ for script in self.scripts:
+ retval += script.__str__()
+
+ retval += self.packages.__str__()
+
+ return retval
+
+ def _insertSorted(self, lst, obj):
+ length = len(lst)
+ i = 0
+
+ while i < length:
+ # If the two classes have the same name, it's because we are
+ # overriding an existing class with one from a later kickstart
+ # version, so remove the old one in favor of the new one.
+ if obj.__class__.__name__ > lst[i].__class__.__name__:
+ i += 1
+ elif obj.__class__.__name__ == lst[i].__class__.__name__:
+ lst[i] = obj
+ return
+ elif obj.__class__.__name__ < lst[i].__class__.__name__:
+ break
+
+ if i >= length:
+ lst.append(obj)
+ else:
+ lst.insert(i, obj)
+
+ def _setCommand(self, cmdObj):
+ # Add an attribute on this version object. We need this to provide a
+ # way for clients to access the command objects. We also need to strip
+ # off the version part from the front of the name.
+ if cmdObj.__class__.__name__.find("_") != -1:
+ name = unicode(cmdObj.__class__.__name__.split("_", 1)[1])
+ else:
+ name = unicode(cmdObj.__class__.__name__).lower()
+
+ setattr(self, name.lower(), cmdObj)
+
+ # Also, add the object into the _writeOrder dict in the right place.
+ if cmdObj.writePriority is not None:
+ if self._writeOrder.has_key(cmdObj.writePriority):
+ self._insertSorted(self._writeOrder[cmdObj.writePriority], cmdObj)
+ else:
+ self._writeOrder[cmdObj.writePriority] = [cmdObj]
+
+ def _registerCommands(self, mapping=None, dataMapping=None, commandUpdates=None,
+ dataUpdates=None):
+ if mapping == {} or mapping == None:
+ from pykickstart.handlers.control import commandMap
+ cMap = commandMap[self.version]
+ else:
+ cMap = mapping
+
+ if dataMapping == {} or dataMapping == None:
+ from pykickstart.handlers.control import dataMap
+ dMap = dataMap[self.version]
+ else:
+ dMap = dataMapping
+
+ if type(commandUpdates) == types.DictType:
+ cMap.update(commandUpdates)
+
+ if type(dataUpdates) == types.DictType:
+ dMap.update(dataUpdates)
+
+ for (cmdName, cmdClass) in cMap.iteritems():
+ # First make sure we haven't instantiated this command handler
+ # already. If we have, we just need to make another mapping to
+ # it in self.commands.
+ cmdObj = None
+
+ for (key, val) in self.commands.iteritems():
+ if val.__class__.__name__ == cmdClass.__name__:
+ cmdObj = val
+ break
+
+ # If we didn't find an instance in self.commands, create one now.
+ if cmdObj == None:
+ cmdObj = cmdClass()
+ self._setCommand(cmdObj)
+
+ # Finally, add the mapping to the commands dict.
+ self.commands[cmdName] = cmdObj
+ self.commands[cmdName].handler = self
+
+ # We also need to create attributes for the various data objects.
+ # No checks here because dMap is a bijection. At least, that's what
+ # the comment says. Hope no one screws that up.
+ for (dataName, dataClass) in dMap.iteritems():
+ setattr(self, dataName, dataClass)
+
+ def dispatcher(self, args, lineno):
+ """Call the appropriate KickstartCommand handler for the current line
+ in the kickstart file. A handler for the current command should
+ be registered, though a handler of None is not an error. Returns
+ the data object returned by KickstartCommand.parse.
+
+ args -- A list of arguments to the current command
+ lineno -- The line number in the file, for error reporting
+ """
+ cmd = args[0]
+
+ if not self.commands.has_key(cmd):
+ raise KickstartParseError (formatErrorMsg(lineno, msg=_("Unknown command: %s" % cmd)))
+ elif self.commands[cmd] != None:
+ self.commands[cmd].currentCmd = cmd
+ self.commands[cmd].currentLine = self.currentLine
+ self.commands[cmd].lineno = lineno
+
+ # The parser returns the data object that was modified. This could
+ # be a BaseData subclass that should be put into a list, or it
+ # could be the command handler object itself.
+ obj = self.commands[cmd].parse(args[1:])
+ lst = self.commands[cmd].dataList()
+ if lst is not None:
+ lst.append(obj)
+
+ return obj
+
+ def maskAllExcept(self, lst):
+ """Set all entries in the commands dict to None, except the ones in
+ the lst. All other commands will not be processed.
+ """
+ self._writeOrder = {}
+
+ for (key, val) in self.commands.iteritems():
+ if not key in lst:
+ self.commands[key] = None
+
+ def hasCommand(self, cmd):
+ """Return true if there is a handler for the string cmd."""
+ return hasattr(self, cmd)
+
+
+###
+### DATA
+###
+class BaseData(KickstartObject):
+ """The base class for all data objects. This is an abstract class."""
+ removedKeywords = []
+ removedAttrs = []
+
+ def __init__(self, *args, **kwargs):
+ """Create a new BaseData instance.
+
+ lineno -- Line number in the ks-file where this object was defined
+ """
+
+ # We don't want people using this class by itself.
+ if self.__class__ is BaseData:
+ raise TypeError ("BaseData is an abstract class.")
+
+ KickstartObject.__init__(self, *args, **kwargs)
+ self.lineno = 0
+
+ def __str__(self):
+ """Return a string formatted for output to a kickstart file."""
+ return ""
+
+ def __call__(self, *args, **kwargs):
+ """Set multiple attributes on a subclass of BaseData at once via
+ keyword arguments. Valid attributes are anything specified in a
+ subclass, but unknown attributes will be ignored.
+ """
+ for (key, val) in kwargs.items():
+ # Ignore setting attributes that were removed in a subclass, as
+ # if they were unknown attributes.
+ if key in self.removedAttrs:
+ continue
+
+ if hasattr(self, key):
+ setattr(self, key, val)
+
+ def deleteRemovedAttrs(self):
+ """Remove all attributes from self that are given in the removedAttrs
+ list. This method should be called from __init__ in a subclass,
+ but only after the superclass's __init__ method has been called.
+ """
+ for attr in filter(lambda k: hasattr(self, k), self.removedAttrs):
+ delattr(self, attr)
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2009 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+import authconfig, autopart, autostep, bootloader, clearpart, device
+import deviceprobe, displaymode, dmraid, driverdisk, fcoe, firewall, firstboot
+import group, ignoredisk, interactive, iscsi, iscsiname, key, keyboard, lang
+import langsupport, lilocheck, logging, logvol, mediacheck, method, monitor
+import mouse, multipath, network, partition, raid, reboot, repo, rescue, rootpw
+import selinux, services, skipx, sshpw, timezone, updates, upgrade, user, vnc
+import volgroup, xconfig, zerombr, zfcp
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+
+class FC3_Authconfig(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, *args, **kwargs)
+ self.authconfig = kwargs.get("authconfig", "")
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.authconfig:
+ retval += "# System authorization information\nauth %s\n" % self.authconfig
+
+ return retval
+
+ def parse(self, args):
+ self.authconfig = self.currentLine[len(self.currentCmd):].strip()
+ return self
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007, 2008 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_AutoPart(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=100, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.autopart = kwargs.get("autopart", False)
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.autopart:
+ retval += "autopart\n"
+
+ return retval
+
+ def parse(self, args):
+ if len(args) > 0:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Kickstart command %s does not take any arguments") % "autopart"))
+
+ self.autopart = True
+ return self
+
+class F9_AutoPart(FC3_AutoPart):
+ removedKeywords = FC3_AutoPart.removedKeywords
+ removedAttrs = FC3_AutoPart.removedAttrs
+
+ def __init__(self, writePriority=100, *args, **kwargs):
+ FC3_AutoPart.__init__(self, writePriority=writePriority, *args, **kwargs)
+ self.encrypted = kwargs.get("encrypted", False)
+ self.passphrase = kwargs.get("passphrase", "")
+
+ self.op = self._getParser()
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.autopart:
+ retval += "autopart"
+
+ if self.encrypted:
+ retval += " --encrypted"
+
+ if self.passphrase != "":
+ retval += " --passphrase=\"%s\""% self.passphrase
+
+ if retval != "":
+ retval += "\n"
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--encrypted", action="store_true", default=False)
+ op.add_option("--passphrase")
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ self._setToSelf(self.op, opts)
+ self.autopart = True
+ return self
+
+class F12_AutoPart(F9_AutoPart):
+ removedKeywords = F9_AutoPart.removedKeywords
+ removedAttrs = F9_AutoPart.removedAttrs
+
+ def __init__(self, writePriority=100, *args, **kwargs):
+ F9_AutoPart.__init__(self, writePriority=writePriority, *args, **kwargs)
+
+ self.escrowcert = kwargs.get("escrowcert", "")
+ self.backuppassphrase = kwargs.get("backuppassphrase", False)
+
+ def __str__(self):
+ retval = F9_AutoPart.__str__(self)
+
+ if self.encrypted and self.escrowcert != "":
+ retval = retval.strip()
+
+ retval += " --escrowcert=\"%s\"" % self.escrowcert
+
+ if self.backuppassphrase:
+ retval += " --backuppassphrase"
+
+ retval += "\n"
+
+ return retval
+
+ def _getParser(self):
+ op = F9_AutoPart._getParser(self)
+ op.add_option("--escrowcert")
+ op.add_option("--backuppassphrase", action="store_true", default=False)
+ return op
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.options import *
+
+class FC3_AutoStep(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.autostep = kwargs.get("autostep", False)
+ self.autoscreenshot = kwargs.get("autoscreenshot", False)
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.autostep:
+ if self.autoscreenshot:
+ retval += "autostep --autoscreenshot\n"
+ else:
+ retval += "autostep\n"
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--autoscreenshot", dest="autoscreenshot",
+ action="store_true", default=False)
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ self._setToSelf(self.op, opts)
+ self.autostep = True
+ return self
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.options import *
+
+class FC3_Bootloader(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=10, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.driveorder = kwargs.get("driveorder", [])
+ self.appendLine = kwargs.get("appendLine", "")
+ self.forceLBA = kwargs.get("forceLBA", False)
+ self.linear = kwargs.get("linear", True)
+ self.location = kwargs.get("location", "")
+ self.md5pass = kwargs.get("md5pass", "")
+ self.password = kwargs.get("password", "")
+ self.upgrade = kwargs.get("upgrade", False)
+ self.useLilo = kwargs.get("useLilo", False)
+
+ self.deleteRemovedAttrs()
+
+ def _getArgsAsStr(self):
+ retval = ""
+
+ if self.appendLine != "":
+ retval += " --append=\"%s\"" % self.appendLine
+ if self.linear:
+ retval += " --linear"
+ if self.location:
+ retval += " --location=%s" % self.location
+ if hasattr(self, "forceLBA") and self.forceLBA:
+ retval += " --lba32"
+ if self.password != "":
+ retval += " --password=\"%s\"" % self.password
+ if self.md5pass != "":
+ retval += " --md5pass=\"%s\"" % self.md5pass
+ if self.upgrade:
+ retval += " --upgrade"
+ if self.useLilo:
+ retval += " --useLilo"
+ if len(self.driveorder) > 0:
+ retval += " --driveorder=\"%s\"" % ",".join(self.driveorder)
+
+ return retval
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.location != "":
+ retval += "# System bootloader configuration\nbootloader"
+ retval += self._getArgsAsStr() + "\n"
+
+ return retval
+
+ def _getParser(self):
+ def driveorder_cb (option, opt_str, value, parser):
+ for d in value.split(','):
+ parser.values.ensure_value(option.dest, []).append(d)
+
+ op = KSOptionParser()
+ op.add_option("--append", dest="appendLine")
+ op.add_option("--linear", dest="linear", action="store_true",
+ default=True)
+ op.add_option("--nolinear", dest="linear", action="store_false")
+ op.add_option("--location", dest="location", type="choice",
+ default="mbr",
+ choices=["mbr", "partition", "none", "boot"])
+ op.add_option("--lba32", dest="forceLBA", action="store_true",
+ default=False)
+ op.add_option("--password", dest="password", default="")
+ op.add_option("--md5pass", dest="md5pass", default="")
+ op.add_option("--upgrade", dest="upgrade", action="store_true",
+ default=False)
+ op.add_option("--useLilo", dest="useLilo", action="store_true",
+ default=False)
+ op.add_option("--driveorder", dest="driveorder", action="callback",
+ callback=driveorder_cb, nargs=1, type="string")
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ self._setToSelf(self.op, opts)
+
+ if self.currentCmd == "lilo":
+ self.useLilo = True
+
+ return self
+
+class FC4_Bootloader(FC3_Bootloader):
+ removedKeywords = FC3_Bootloader.removedKeywords + ["linear", "useLilo"]
+ removedAttrs = FC3_Bootloader.removedAttrs + ["linear", "useLilo"]
+
+ def __init__(self, writePriority=10, *args, **kwargs):
+ FC3_Bootloader.__init__(self, writePriority, *args, **kwargs)
+
+ def _getArgsAsStr(self):
+ retval = ""
+ if self.appendLine != "":
+ retval += " --append=\"%s\"" % self.appendLine
+ if self.location:
+ retval += " --location=%s" % self.location
+ if hasattr(self, "forceLBA") and self.forceLBA:
+ retval += " --lba32"
+ if self.password != "":
+ retval += " --password=\"%s\"" % self.password
+ if self.md5pass != "":
+ retval += " --md5pass=\"%s\"" % self.md5pass
+ if self.upgrade:
+ retval += " --upgrade"
+ if len(self.driveorder) > 0:
+ retval += " --driveorder=\"%s\"" % ",".join(self.driveorder)
+ return retval
+
+ def _getParser(self):
+ op = FC3_Bootloader._getParser(self)
+ op.remove_option("--linear")
+ op.remove_option("--nolinear")
+ op.remove_option("--useLilo")
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ self._setToSelf(self.op, opts)
+ return self
+
+class F8_Bootloader(FC4_Bootloader):
+ removedKeywords = FC4_Bootloader.removedKeywords
+ removedAttrs = FC4_Bootloader.removedAttrs
+
+ def __init__(self, writePriority=10, *args, **kwargs):
+ FC4_Bootloader.__init__(self, writePriority, *args, **kwargs)
+
+ self.timeout = kwargs.get("timeout", None)
+ self.default = kwargs.get("default", "")
+
+ def _getArgsAsStr(self):
+ ret = FC4_Bootloader._getArgsAsStr(self)
+
+ if self.timeout is not None:
+ ret += " --timeout=%d" %(self.timeout,)
+ if self.default:
+ ret += " --default=%s" %(self.default,)
+
+ return ret
+
+ def _getParser(self):
+ op = FC4_Bootloader._getParser(self)
+ op.add_option("--timeout", dest="timeout", type="int")
+ op.add_option("--default", dest="default")
+ return op
+
+class F12_Bootloader(F8_Bootloader):
+ removedKeywords = F8_Bootloader.removedKeywords
+ removedAttrs = F8_Bootloader.removedAttrs
+
+ def _getParser(self):
+ op = F8_Bootloader._getParser(self)
+ op.add_option("--lba32", dest="forceLBA", deprecated=1, action="store_true")
+ return op
+
+class F14_Bootloader(F12_Bootloader):
+ removedKeywords = F12_Bootloader.removedKeywords + ["forceLBA"]
+ removedAttrs = F12_Bootloader.removedKeywords + ["forceLBA"]
+
+ def _getParser(self):
+ op = F12_Bootloader._getParser(self)
+ op.remove_option("--lba32")
+ return op
+
+class F15_Bootloader(F14_Bootloader):
+ removedKeywords = F14_Bootloader.removedKeywords
+ removedAttrs = F14_Bootloader.removedAttrs
+
+ def __init__(self, writePriority=10, *args, **kwargs):
+ F14_Bootloader.__init__(self, writePriority, *args, **kwargs)
+
+ self.isCrypted = kwargs.get("isCrypted", False)
+
+ def _getArgsAsStr(self):
+ ret = F14_Bootloader._getArgsAsStr(self)
+
+ if self.isCrypted:
+ ret += " --iscrypted"
+
+ return ret
+
+ def _getParser(self):
+ def password_cb(option, opt_str, value, parser):
+ parser.values.isCrypted = True
+ parser.values.password = value
+
+ op = F14_Bootloader._getParser(self)
+ op.add_option("--iscrypted", dest="isCrypted", action="store_true", default=False)
+ op.add_option("--md5pass", action="callback", callback=password_cb, nargs=1, type="string")
+ return op
+
+class RHEL5_Bootloader(FC4_Bootloader):
+ removedKeywords = FC4_Bootloader.removedKeywords
+ removedAttrs = FC4_Bootloader.removedAttrs
+
+ def __init__(self, writePriority=10, *args, **kwargs):
+ FC4_Bootloader.__init__(self, writePriority, *args, **kwargs)
+
+ self.hvArgs = kwargs.get("hvArgs", "")
+
+ def _getArgsAsStr(self):
+ ret = FC4_Bootloader._getArgsAsStr(self)
+
+ if self.hvArgs:
+ ret += " --hvargs=\"%s\"" %(self.hvArgs,)
+
+ return ret
+
+ def _getParser(self):
+ op = FC4_Bootloader._getParser(self)
+ op.add_option("--hvargs", dest="hvArgs", type="string")
+ return op
+
+class RHEL6_Bootloader(F12_Bootloader):
+ removedKeywords = F12_Bootloader.removedKeywords
+ removedAttrs = F12_Bootloader.removedAttrs
+
+ def __init__(self, writePriority=10, *args, **kwargs):
+ F12_Bootloader.__init__(self, writePriority, *args, **kwargs)
+
+ self.isCrypted = kwargs.get("isCrypted", False)
+
+ def _getArgsAsStr(self):
+ ret = F12_Bootloader._getArgsAsStr(self)
+
+ if self.isCrypted:
+ ret += " --iscrypted"
+
+ return ret
+
+ def _getParser(self):
+ def password_cb(option, opt_str, value, parser):
+ parser.values.isCrypted = True
+ parser.values.password = value
+
+ op = F12_Bootloader._getParser(self)
+ op.add_option("--iscrypted", dest="isCrypted", action="store_true", default=False)
+ op.add_option("--md5pass", action="callback", callback=password_cb, nargs=1, type="string")
+ return op
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.constants import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+class FC3_ClearPart(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=120, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.drives = kwargs.get("drives", [])
+ self.initAll = kwargs.get("initAll", False)
+ self.type = kwargs.get("type", None)
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.type is None:
+ return retval
+
+ if self.type == CLEARPART_TYPE_NONE:
+ clearstr = "--none"
+ elif self.type == CLEARPART_TYPE_LINUX:
+ clearstr = "--linux"
+ elif self.type == CLEARPART_TYPE_ALL:
+ clearstr = "--all"
+ else:
+ clearstr = ""
+
+ if self.initAll:
+ initstr = "--initlabel"
+ else:
+ initstr = ""
+
+ if len(self.drives) > 0:
+ drivestr = "--drives=" + ",".join(self.drives)
+ else:
+ drivestr = ""
+
+ retval += "# Partition clearing information\nclearpart %s %s %s\n" % (clearstr, initstr, drivestr)
+ return retval
+
+ def _getParser(self):
+ def drive_cb (option, opt_str, value, parser):
+ for d in value.split(','):
+ parser.values.ensure_value(option.dest, []).append(d)
+
+ op = KSOptionParser()
+ op.add_option("--all", dest="type", action="store_const",
+ const=CLEARPART_TYPE_ALL)
+ op.add_option("--drives", dest="drives", action="callback",
+ callback=drive_cb, nargs=1, type="string")
+ op.add_option("--initlabel", dest="initAll", action="store_true",
+ default=False)
+ op.add_option("--linux", dest="type", action="store_const",
+ const=CLEARPART_TYPE_LINUX)
+ op.add_option("--none", dest="type", action="store_const",
+ const=CLEARPART_TYPE_NONE)
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ self._setToSelf(self.op, opts)
+ return self
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.options import *
+
+import gettext
+import warnings
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class F8_DeviceData(BaseData):
+ removedKeywords = BaseData.removedKeywords
+ removedAttrs = BaseData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ BaseData.__init__(self, *args, **kwargs)
+ self.moduleName = kwargs.get("moduleName", "")
+ self.moduleOpts = kwargs.get("moduleOpts", "")
+
+ def __eq__(self, y):
+ return self.moduleName == y.moduleName
+
+ def __str__(self):
+ retval = BaseData.__str__(self)
+
+ if self.moduleName != "":
+ retval += "device %s" % self.moduleName
+
+ if self.moduleOpts != "":
+ retval += " --opts=\"%s\"" % self.moduleOpts
+
+ return retval + "\n"
+
+class FC3_Device(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.type = kwargs.get("type", "")
+ self.moduleName = kwargs.get("moduleName", "")
+ self.moduleOpts = kwargs.get("moduleOpts", "")
+
+ def __eq__(self, y):
+ return self.moduleName == y.moduleName
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.moduleName != "":
+ retval += "device %s %s" % (self.type, self.moduleName)
+
+ if self.moduleOpts != "":
+ retval += " --opts=\"%s\"" % self.moduleOpts
+
+ return retval + "\n"
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--opts", dest="moduleOpts", default="")
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+
+ if len(extra) != 2:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("device command requires two arguments: module type and name")))
+
+ self.moduleOpts = opts.moduleOpts
+ self.type = extra[0]
+ self.moduleName = extra[1]
+ return self
+
+class F8_Device(FC3_Device):
+ removedKeywords = FC3_Device.removedKeywords
+ removedAttrs = FC3_Device.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ FC3_Device.__init__(self, writePriority, *args, **kwargs)
+ self.deviceList = kwargs.get("deviceList", [])
+
+ def __str__(self):
+ retval = ""
+ for device in self.deviceList:
+ retval += device.__str__()
+
+ return retval
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+
+ if len(extra) != 1:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("%s command requires a single argument: %s") % ("device", "module name")))
+
+ dd = F8_DeviceData()
+ self._setToObj(self.op, opts, dd)
+ dd.lineno = self.lineno
+ dd.moduleName = extra[0]
+
+ # Check for duplicates in the data list.
+ if dd in self.dataList():
+ warnings.warn(_("A module with the name %s has already been defined.") % dd.moduleName)
+
+ return dd
+
+ def dataList(self):
+ return self.deviceList
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+
+class FC3_DeviceProbe(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.deviceprobe = kwargs.get("deviceprobe", "")
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.deviceprobe != "":
+ retval += "deviceprobe %s\n" % self.deviceprobe
+
+ return retval
+
+ def parse(self, args):
+ self.deviceprobe = " ".join(args)
+ return self
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.constants import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_DisplayMode(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+ self.displayMode = kwargs.get("displayMode", None)
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.displayMode is None:
+ return retval
+
+ if self.displayMode == DISPLAY_MODE_CMDLINE:
+ retval += "cmdline\n"
+ elif self.displayMode == DISPLAY_MODE_GRAPHICAL:
+ retval += "# Use graphical install\ngraphical\n"
+ elif self.displayMode == DISPLAY_MODE_TEXT:
+ retval += "# Use text mode install\ntext\n"
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+
+ if len(extra) > 0:
+ raise KickstartParseError (formatErrorMsg(self.lineno, msg=_("Kickstart command %s does not take any arguments") % self.currentCmd))
+
+ if self.currentCmd == "cmdline":
+ self.displayMode = DISPLAY_MODE_CMDLINE
+ elif self.currentCmd == "graphical":
+ self.displayMode = DISPLAY_MODE_GRAPHICAL
+ elif self.currentCmd == "text":
+ self.displayMode = DISPLAY_MODE_TEXT
+
+ return self
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+# Peter Jones <pjones@redhat.com>
+#
+# Copyright 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+import warnings
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC6_DmRaidData(BaseData):
+ removedKeywords = BaseData.removedKeywords
+ removedAttrs = BaseData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ BaseData.__init__(self, *args, **kwargs)
+
+ self.name = kwargs.get("name", "")
+ self.devices = kwargs.get("devices", [])
+ self.dmset = kwargs.get("dmset", None)
+
+ def __eq__(self, y):
+ return self.name == y.name and self.devices == y.devices
+
+ def __str__(self):
+ retval = BaseData.__str__(self)
+ retval += "dmraid --name=%s" % self.name
+
+ for dev in self.devices:
+ retval += " --dev=\"%s\"" % dev
+
+ return retval + "\n"
+
+class FC6_DmRaid(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=60, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.dmraids = kwargs.get("dmraids", [])
+
+ def __str__(self):
+ retval = ""
+ for dm in self.dmraids:
+ retval += dm.__str__()
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--name", dest="name", action="store", type="string",
+ required=1)
+ op.add_option("--dev", dest="devices", action="append", type="string",
+ required=1)
+ return op
+
+ def parse(self, args):
+ dm = FC6_DmRaidData()
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ dm.name = dm.name.split('/')[-1]
+ self._setToObj(self.op, opts, dm)
+ dm.lineno = self.lineno
+
+ # Check for duplicates in the data list.
+ if dm in self.dataList():
+ warnings.warn(_("A DM RAID device with the name %s and devices %s has already been defined.") % (dm.name, dm.devices))
+
+ return dm
+
+ def dataList(self):
+ return self.dmraids
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007, 2008 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_DriverDiskData(BaseData):
+ removedKeywords = BaseData.removedKeywords
+ removedAttrs = BaseData.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ BaseData.__init__(self, *args, **kwargs)
+
+ self.partition = kwargs.get("partition", "")
+ self.source = kwargs.get("source", "")
+ self.type = kwargs.get("type", "")
+
+ def _getArgsAsStr(self):
+ retval = ""
+
+ if self.partition:
+ retval += "%s" % self.partition
+
+ if hasattr(self, "type") and self.type:
+ retval += " --type=%s" % self.type
+ elif self.source:
+ retval += "--source=%s" % self.source
+ return retval
+
+ def __str__(self):
+ retval = BaseData.__str__(self)
+ retval += "driverdisk %s\n" % self._getArgsAsStr()
+ return retval
+
+class FC4_DriverDiskData(FC3_DriverDiskData):
+ removedKeywords = FC3_DriverDiskData.removedKeywords
+ removedAttrs = FC3_DriverDiskData.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ FC3_DriverDiskData.__init__(self, *args, **kwargs)
+ self.deleteRemovedAttrs()
+
+ self.biospart = kwargs.get("biospart", "")
+
+ def _getArgsAsStr(self):
+ retval = ""
+
+ if self.partition:
+ retval += "%s" % self.partition
+
+ if hasattr(self, "type") and self.type:
+ retval += " --type=%s" % self.type
+ elif self.source:
+ retval += "--source=%s" % self.source
+ elif self.biospart:
+ retval += "--biospart=%s" % self.biospart
+
+ return retval
+
+class F12_DriverDiskData(FC4_DriverDiskData):
+ removedKeywords = FC4_DriverDiskData.removedKeywords + ["type"]
+ removedAttrs = FC4_DriverDiskData.removedAttrs + ["type"]
+
+ def __init__(self, *args, **kwargs):
+ FC4_DriverDiskData.__init__(self, *args, **kwargs)
+ self.deleteRemovedAttrs()
+
+F14_DriverDiskData = F12_DriverDiskData
+
+class FC3_DriverDisk(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.driverdiskList = kwargs.get("driverdiskList", [])
+
+ def __str__(self):
+ retval = ""
+ for dd in self.driverdiskList:
+ retval += dd.__str__()
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--source")
+ op.add_option("--type")
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+
+ if len(extra) > 1:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Only one partition may be specified for driverdisk command.")))
+
+ if len(extra) == 1 and opts.source:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Only one of --source and partition may be specified for driverdisk command.")))
+
+ if not extra and not opts.source:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("One of --source or partition must be specified for driverdisk command.")))
+
+ ddd = self.handler.DriverDiskData()
+ self._setToObj(self.op, opts, ddd)
+ ddd.lineno = self.lineno
+ if len(extra) == 1:
+ ddd.partition = extra[0]
+
+ return ddd
+
+ def dataList(self):
+ return self.driverdiskList
+
+class FC4_DriverDisk(FC3_DriverDisk):
+ removedKeywords = FC3_DriverDisk.removedKeywords
+ removedAttrs = FC3_DriverDisk.removedKeywords
+
+ def _getParser(self):
+ op = FC3_DriverDisk._getParser(self)
+ op.add_option("--biospart")
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+
+ if len(extra) > 1:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Only one partition may be specified for driverdisk command.")))
+
+ if len(extra) == 1 and opts.source:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Only one of --source and partition may be specified for driverdisk command.")))
+ elif len(extra) == 1 and opts.biospart:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Only one of --biospart and partition may be specified for driverdisk command.")))
+ elif opts.source and opts.biospart:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Only one of --biospart and --source may be specified for driverdisk command.")))
+
+ if not extra and not opts.source and not opts.biospart:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("One of --source, --biospart, or partition must be specified for driverdisk command.")))
+
+ ddd = self.handler.DriverDiskData()
+ self._setToObj(self.op, opts, ddd)
+ ddd.lineno = self.lineno
+ if len(extra) == 1:
+ ddd.partition = extra[0]
+
+ return ddd
+
+class F12_DriverDisk(FC4_DriverDisk):
+ removedKeywords = FC4_DriverDisk.removedKeywords
+ removedAttrs = FC4_DriverDisk.removedKeywords
+
+ def _getParser(self):
+ op = FC4_DriverDisk._getParser(self)
+ op.add_option("--type", deprecated=1)
+ return op
+
+class F14_DriverDisk(F12_DriverDisk):
+ removedKeywords = F12_DriverDisk.removedKeywords
+ removedAttrs = F12_DriverDisk.removedKeywords
+
+ def _getParser(self):
+ op = F12_DriverDisk._getParser(self)
+ op.remove_option("--type")
+ return op
--- /dev/null
+#
+# Hans de Goede <hdegoede@redhat.com>
+#
+# Copyright 2009 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.options import *
+
+import gettext
+import warnings
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class F12_FcoeData(BaseData):
+ removedKeywords = BaseData.removedKeywords
+ removedAttrs = BaseData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ BaseData.__init__(self, *args, **kwargs)
+ self.nic = kwargs.get("nic", None)
+
+ def __eq__(self, y):
+ return self.nic == y.nic
+
+ def _getArgsAsStr(self):
+ retval = ""
+
+ if self.nic:
+ retval += " --nic=%s" % self.nic
+
+ return retval
+
+ def __str__(self):
+ retval = BaseData.__str__(self)
+ retval += "fcoe%s\n" % self._getArgsAsStr()
+ return retval
+
+class F13_FcoeData(F12_FcoeData):
+ removedKeywords = F12_FcoeData.removedKeywords
+ removedAttrs = F12_FcoeData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ F12_FcoeData.__init__(self, *args, **kwargs)
+ self.dcb = kwargs.get("dcb", False)
+
+ def _getArgsAsStr(self):
+ retval = F12_FcoeData._getArgsAsStr(self)
+
+ if self.dcb:
+ retval += " --dcb"
+
+ return retval
+
+class F12_Fcoe(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=71, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+ self.fcoe = kwargs.get("fcoe", [])
+
+ def __str__(self):
+ retval = ""
+ for fcoe in self.fcoe:
+ retval += fcoe.__str__()
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--nic", dest="nic", required=1)
+ return op
+
+ def parse(self, args):
+ zd = self.handler.FcoeData()
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ if len(extra) > 0:
+ mapping = {"command": "fcoe", "options": extra}
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Unexpected arguments to %(command)s command: %(options)s") % mapping))
+
+ self._setToObj(self.op, opts, zd)
+ zd.lineno = self.lineno
+
+ # Check for duplicates in the data list.
+ if zd in self.dataList():
+ warnings.warn(_("A FCOE device with the name %s has already been defined.") % zd.nic)
+
+ return zd
+
+ def dataList(self):
+ return self.fcoe
+
+class F13_Fcoe(F12_Fcoe):
+ removedKeywords = F12_Fcoe.removedKeywords
+ removedAttrs = F12_Fcoe.removedAttrs
+
+ def _getParser(self):
+ op = F12_Fcoe._getParser(self)
+ op.add_option("--dcb", dest="dcb", action="store_true", default=False)
+ return op
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_Firewall(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.enabled = kwargs.get("enabled", None)
+ self.ports = kwargs.get("ports", [])
+ self.trusts = kwargs.get("trusts", [])
+
+ def __str__(self):
+ extra = []
+ filteredPorts = []
+
+ retval = KickstartCommand.__str__(self)
+
+ if self.enabled is None:
+ return retval
+
+ if self.enabled:
+ # It's possible we have words in the ports list instead of
+ # port:proto (s-c-kickstart may do this). So, filter those
+ # out into their own list leaving what we expect.
+ for port in self.ports:
+ if port == "ssh":
+ extra.append(" --ssh")
+ elif port == "telnet":
+ extra.append(" --telnet")
+ elif port == "smtp":
+ extra.append(" --smtp")
+ elif port == "http":
+ extra.append(" --http")
+ elif port == "ftp":
+ extra.append(" --ftp")
+ else:
+ filteredPorts.append(port)
+
+ # All the port:proto strings go into a comma-separated list.
+ portstr = ",".join(filteredPorts)
+ if len(portstr) > 0:
+ portstr = " --port=" + portstr
+ else:
+ portstr = ""
+
+ extrastr = "".join(extra)
+ truststr = ",".join(self.trusts)
+
+ if len(truststr) > 0:
+ truststr = " --trust=" + truststr
+
+ # The output port list consists only of port:proto for
+ # everything that we don't recognize, and special options for
+ # those that we do.
+ retval += "# Firewall configuration\nfirewall --enabled%s%s%s\n" % (extrastr, portstr, truststr)
+ else:
+ retval += "# Firewall configuration\nfirewall --disabled\n"
+
+ return retval
+
+ def _getParser(self):
+ def firewall_port_cb (option, opt_str, value, parser):
+ for p in value.split(","):
+ p = p.strip()
+ if p.find(":") == -1:
+ p = "%s:tcp" % p
+ parser.values.ensure_value(option.dest, []).append(p)
+
+ op = KSOptionParser(mapping={"ssh":["22:tcp"], "telnet":["23:tcp"],
+ "smtp":["25:tcp"], "http":["80:tcp", "443:tcp"],
+ "ftp":["21:tcp"]})
+
+ op.add_option("--disable", "--disabled", dest="enabled",
+ action="store_false")
+ op.add_option("--enable", "--enabled", dest="enabled",
+ action="store_true", default=True)
+ op.add_option("--ftp", "--http", "--smtp", "--ssh", "--telnet",
+ dest="ports", action="map_extend")
+ op.add_option("--high", deprecated=1)
+ op.add_option("--medium", deprecated=1)
+ op.add_option("--port", dest="ports", action="callback",
+ callback=firewall_port_cb, nargs=1, type="string")
+ op.add_option("--trust", dest="trusts", action="append")
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+
+ if len(extra) != 0:
+ mapping = {"command": "firewall", "options": extra}
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Unexpected arguments to %(command)s command: %(options)s") % mapping))
+
+ self._setToSelf(self.op, opts)
+ return self
+
+class F9_Firewall(FC3_Firewall):
+ removedKeywords = FC3_Firewall.removedKeywords
+ removedAttrs = FC3_Firewall.removedAttrs
+
+ def _getParser(self):
+ op = FC3_Firewall._getParser(self)
+ op.remove_option("--high")
+ op.remove_option("--medium")
+ return op
+
+class F10_Firewall(F9_Firewall):
+ removedKeywords = F9_Firewall.removedKeywords
+ removedAttrs = F9_Firewall.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ F9_Firewall.__init__(self, writePriority, *args, **kwargs)
+ self.services = kwargs.get("services", [])
+
+ def __str__(self):
+ if self.enabled is None:
+ return ""
+
+ retval = F9_Firewall.__str__(self)
+ if self.enabled:
+ retval = retval.strip()
+
+ svcstr = ",".join(self.services)
+ if len(svcstr) > 0:
+ svcstr = " --service=" + svcstr
+ else:
+ svcstr = ""
+
+ return retval + "%s\n" % svcstr
+ else:
+ return retval
+
+ def _getParser(self):
+ def service_cb (option, opt_str, value, parser):
+ # python2.4 does not support action="append_const" that we were
+ # using for these options. Instead, we have to fake it by
+ # appending whatever the option string is to the service list.
+ if not value:
+ parser.values.ensure_value(option.dest, []).append(opt_str[2:])
+ return
+
+ for p in value.split(","):
+ p = p.strip()
+ parser.values.ensure_value(option.dest, []).append(p)
+
+ op = F9_Firewall._getParser(self)
+ op.add_option("--service", dest="services", action="callback",
+ callback=service_cb, nargs=1, type="string")
+ op.add_option("--ftp", dest="services", action="callback",
+ callback=service_cb)
+ op.add_option("--http", dest="services", action="callback",
+ callback=service_cb)
+ op.add_option("--smtp", dest="services", action="callback",
+ callback=service_cb)
+ op.add_option("--ssh", dest="services", action="callback",
+ callback=service_cb)
+ op.add_option("--telnet", deprecated=1)
+ return op
+
+class F14_Firewall(F10_Firewall):
+ removedKeywords = F10_Firewall.removedKeywords + ["telnet"]
+ removedAttrs = F10_Firewall.removedAttrs + ["telnet"]
+
+ def _getParser(self):
+ op = F10_Firewall._getParser(self)
+ op.remove_option("--telnet")
+ return op
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.constants import *
+from pykickstart.options import *
+
+class FC3_Firstboot(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.firstboot = kwargs.get("firstboot", None)
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.firstboot is None:
+ return retval
+
+ if self.firstboot == FIRSTBOOT_SKIP:
+ retval += "firstboot --disable\n"
+ elif self.firstboot == FIRSTBOOT_DEFAULT:
+ retval += "# Run the Setup Agent on first boot\nfirstboot --enable\n"
+ elif self.firstboot == FIRSTBOOT_RECONFIG:
+ retval += "# Run the Setup Agent on first boot\nfirstboot --reconfig\n"
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--disable", "--disabled", dest="firstboot",
+ action="store_const", const=FIRSTBOOT_SKIP)
+ op.add_option("--enable", "--enabled", dest="firstboot",
+ action="store_const", const=FIRSTBOOT_DEFAULT)
+ op.add_option("--reconfig", dest="firstboot", action="store_const",
+ const=FIRSTBOOT_RECONFIG)
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ self.firstboot = opts.firstboot
+ return self
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2009 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.constants import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+import warnings
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class F12_GroupData(BaseData):
+ removedKeywords = BaseData.removedKeywords
+ removedAttrs = BaseData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ BaseData.__init__(self, *args, **kwargs)
+ self.name = kwargs.get("name", "")
+ self.gid = kwargs.get("gid", None)
+
+ def __eq__(self, y):
+ return self.name == y.name
+
+ def __str__(self):
+ retval = BaseData.__str__(self)
+ retval += "group"
+
+ if self.name:
+ retval += " --name=%s" % self.name
+ if self.gid:
+ retval += " --gid=%s" % self.gid
+
+ return retval + "\n"
+
+class F12_Group(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.groupList = kwargs.get("groupList", [])
+
+ def __str__(self):
+ retval = ""
+ for user in self.groupList:
+ retval += user.__str__()
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--name", required=1)
+ op.add_option("--gid", type="int")
+ return op
+
+ def parse(self, args):
+ gd = self.handler.GroupData()
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ self._setToObj(self.op, opts, gd)
+ gd.lineno = self.lineno
+
+ # Check for duplicates in the data list.
+ if gd in self.dataList():
+ warnings.warn(_("A group with the name %s has already been defined.") % gd.name)
+
+ return gd
+
+ def dataList(self):
+ return self.groupList
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007, 2009 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_IgnoreDisk(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.ignoredisk = kwargs.get("ignoredisk", [])
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if len(self.ignoredisk) > 0:
+ retval += "ignoredisk --drives=%s\n" % ",".join(self.ignoredisk)
+
+ return retval
+
+ def _getParser(self):
+ def drive_cb (option, opt_str, value, parser):
+ for d in value.split(','):
+ parser.values.ensure_value(option.dest, []).append(d)
+
+ op = KSOptionParser()
+ op.add_option("--drives", dest="ignoredisk", action="callback",
+ callback=drive_cb, nargs=1, type="string", required=1)
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ self._setToSelf(self.op, opts)
+ return self
+
+class F8_IgnoreDisk(FC3_IgnoreDisk):
+ removedKeywords = FC3_IgnoreDisk.removedKeywords
+ removedAttrs = FC3_IgnoreDisk.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ FC3_IgnoreDisk.__init__(self, writePriority, *args, **kwargs)
+
+ self.onlyuse = kwargs.get("onlyuse", [])
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if len(self.ignoredisk) > 0:
+ retval += "ignoredisk --drives=%s\n" % ",".join(self.ignoredisk)
+ elif len(self.onlyuse) > 0:
+ retval += "ignoredisk --only-use=%s\n" % ",".join(self.onlyuse)
+
+ return retval
+
+ def parse(self, args, errorCheck=True):
+ retval = FC3_IgnoreDisk.parse(self, args)
+
+ if errorCheck:
+ if (len(self.ignoredisk) == 0 and len(self.onlyuse) == 0) or (len(self.ignoredisk) > 0 and (len(self.onlyuse) > 0)):
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("One of --drives or --only-use must be specified for ignoredisk command.")))
+
+ return retval
+
+ def _getParser(self):
+ def drive_cb (option, opt_str, value, parser):
+ for d in value.split(','):
+ parser.values.ensure_value(option.dest, []).append(d)
+
+ op = FC3_IgnoreDisk._getParser(self)
+ op.add_option("--drives", dest="ignoredisk", action="callback",
+ callback=drive_cb, nargs=1, type="string")
+ op.add_option("--only-use", dest="onlyuse", action="callback",
+ callback=drive_cb, nargs=1, type="string")
+ return op
+
+class RHEL6_IgnoreDisk(F8_IgnoreDisk):
+ removedKeywords = F8_IgnoreDisk.removedKeywords
+ removedAttrs = F8_IgnoreDisk.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ F8_IgnoreDisk.__init__(self, writePriority, *args, **kwargs)
+
+ self.interactive = kwargs.get("interactive", False)
+ if self.interactive:
+ self.ignoredisk = []
+
+ def __str__(self):
+ retval = F8_IgnoreDisk.__str__(self)
+
+ if self.interactive:
+ retval = "ignoredisk --interactive\n"
+
+ return retval
+
+ def parse(self, args):
+ retval = F8_IgnoreDisk.parse(self, args, errorCheck=False)
+
+ howmany = 0
+ if len(self.ignoredisk) > 0:
+ howmany += 1
+ if len(self.onlyuse) > 0:
+ howmany += 1
+ if self.interactive:
+ howmany += 1
+ if howmany != 1:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("One of --drives , --only-use , or --interactive must be specified for ignoredisk command.")))
+
+ return retval
+
+ def _getParser(self):
+ op = F8_IgnoreDisk._getParser(self)
+ op.add_option("--interactive", dest="interactive", action="store_true",
+ default=False)
+ return op
+
+F14_IgnoreDisk = RHEL6_IgnoreDisk
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_Interactive(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+ self.interactive = kwargs.get("interactive", False)
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.interactive:
+ retval += "# Use interactive kickstart installation method\ninteractive\n"
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ if len(extra) > 0:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Kickstart command %s does not take any arguments") % "interactive"))
+
+ self.interactive = True
+ return self
+
+class F14_Interactive(DeprecatedCommand):
+ def __init__(self):
+ DeprecatedCommand.__init__(self)
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+# Peter Jones <pjones@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC6_IscsiData(BaseData):
+ removedKeywords = BaseData.removedKeywords
+ removedAttrs = BaseData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ BaseData.__init__(self, *args, **kwargs)
+ self.ipaddr = kwargs.get("ipaddr", "")
+ self.port = kwargs.get("port", "3260")
+ self.target = kwargs.get("target", "")
+ self.user = kwargs.get("user", None)
+ self.password = kwargs.get("password", None)
+
+ def _getArgsAsStr(self):
+ retval = ""
+
+ if self.target != "":
+ retval += " --target=%s" % self.target
+ if self.ipaddr != "":
+ retval += " --ipaddr=%s" % self.ipaddr
+ if self.port != "3260":
+ retval += " --port=%s" % self.port
+ if self.user is not None:
+ retval += " --user=%s" % self.user
+ if self.password is not None:
+ retval += " --password=%s" % self.password
+
+ return retval
+
+ def __str__(self):
+ retval = BaseData.__str__(self)
+ retval += "iscsi%s\n" % self._getArgsAsStr()
+ return retval
+
+class F10_IscsiData(FC6_IscsiData):
+ removedKeywords = FC6_IscsiData.removedKeywords
+ removedAttrs = FC6_IscsiData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ FC6_IscsiData.__init__(self, *args, **kwargs)
+ self.user_in = kwargs.get("user_in", None)
+ self.password_in = kwargs.get("password_in", None)
+
+ def _getArgsAsStr(self):
+ retval = FC6_IscsiData._getArgsAsStr(self)
+
+ if self.user_in is not None:
+ retval += " --reverse-user=%s" % self.user_in
+ if self.password_in is not None:
+ retval += " --reverse-password=%s" % self.password_in
+
+ return retval
+
+class FC6_Iscsi(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=71, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.iscsi = kwargs.get("iscsi", [])
+
+ def __str__(self):
+ retval = ""
+ for iscsi in self.iscsi:
+ retval += iscsi.__str__()
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--target", dest="target", action="store", type="string")
+ op.add_option("--ipaddr", dest="ipaddr", action="store", type="string",
+ required=1)
+ op.add_option("--port", dest="port", action="store", type="string")
+ op.add_option("--user", dest="user", action="store", type="string")
+ op.add_option("--password", dest="password", action="store",
+ type="string")
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+
+ if len(extra) != 0:
+ mapping = {"command": "iscsi", "options": extra}
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Unexpected arguments to %(command)s command: %(options)s") % mapping))
+
+ dd = self.handler.IscsiData()
+ self._setToObj(self.op, opts, dd)
+ dd.lineno = self.lineno
+ return dd
+
+ def dataList(self):
+ return self.iscsi
+
+class F10_Iscsi(FC6_Iscsi):
+ removedKeywords = FC6_Iscsi.removedKeywords
+ removedAttrs = FC6_Iscsi.removedAttrs
+
+ def _getParser(self):
+ op = FC6_Iscsi._getParser(self)
+ op.add_option("--reverse-user", dest="user_in", action="store",
+ type="string")
+ op.add_option("--reverse-password", dest="password_in", action="store",
+ type="string")
+ return op
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+# Peter Jones <pjones@redhat.com>
+#
+# Copyright 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC6_IscsiName(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=70, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+ self.iscsiname = kwargs.get("iscsiname", "")
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.iscsiname != "":
+ retval += "iscsiname %s\n" % self.iscsiname
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ if len(extra) != 1:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Kickstart command %s requires one argument") % "iscsiname"))
+ self.iscsiname = extra[0]
+ return self
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.constants import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class RHEL5_Key(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+ self.key = kwargs.get("key", "")
+ self.skip = kwargs.get("skip", False)
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.key == KS_INSTKEY_SKIP:
+ retval += "key --skip\n"
+ elif self.key != "":
+ retval += "key %s\n" % self.key
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--skip", action="store_true", default=False)
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ self._setToSelf(self.op, opts)
+
+ if self.skip:
+ self.key = KS_INSTKEY_SKIP
+ elif len(extra) != 1:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Kickstart command %s requires one argument") % "key"))
+ else:
+ self.key = extra[0]
+
+ return self
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_Keyboard(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+ self.keyboard = kwargs.get("keyboard", "")
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.keyboard != "":
+ retval += "# System keyboard\nkeyboard %s\n" % self.keyboard
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+
+ if len(extra) != 1:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Kickstart command %s requires one argument") % "keyboard"))
+
+ self.keyboard = extra[0]
+ return self
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_Lang(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+ self.lang = kwargs.get("lang", "")
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.lang != "":
+ retval += "# System language\nlang %s\n" % self.lang
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ if len(extra) != 1:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Kickstart command %s requires one argument") % "lang"))
+
+ self.lang = extra[0]
+ return self
+
+ def apply(self, instroot="/"):
+ if self.lang == "": return
+ f = open(instroot + "/etc/sysconfig/i18n", "w+")
+ f.write("LANG=\"%s\"\n" %(self.lang,))
+ f.close()
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.options import *
+
+class FC3_LangSupport(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.deflang = kwargs.get("deflang", "")
+ self.supported = kwargs.get("supported", [])
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.deflang:
+ retval += "langsupport --default=%s" % self.deflang
+
+ if self.supported:
+ retval += " %s" % " ".join(self.supported)
+
+ return retval + "\n"
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--default", dest="deflang", default="en_US.UTF-8")
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ self._setToSelf(self.op, opts)
+ self.supported = extra
+ return self
+
+class FC5_LangSupport(DeprecatedCommand):
+ def __init__(self):
+ DeprecatedCommand.__init__(self)
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_LiloCheck(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+ self.check = kwargs.get("check", False)
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.check:
+ retval += "lilocheck\n"
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ if len(extra) > 0:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Kickstart command %s does not take any arguments") % "lilocheck"))
+
+ self.check = True
+ return self
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2007, 2009 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC6_Logging(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.host = kwargs.get("host", "")
+ self.level = kwargs.get("level", "info")
+ self.port = kwargs.get("port", "")
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+ retval += "# Installation logging level\nlogging --level=%s" % self.level
+
+ if self.host != "":
+ retval += " --host=%s" % self.host
+
+ if self.port != "":
+ retval += " --port=%s" % self.port
+
+ return retval + "\n"
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--host")
+ op.add_option("--level", type="choice", default="info",
+ choices=["debug", "info", "warning", "error", "critical"])
+ op.add_option("--port")
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+
+ if opts.port and not opts.host:
+ raise KickstartParseError (formatErrorMsg(self.lineno, msg=_("Can't specify --port without --host.")))
+
+ self._setToSelf(self.op, opts)
+ return self
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007, 2008 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+import warnings
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_LogVolData(BaseData):
+ removedKeywords = BaseData.removedKeywords
+ removedAttrs = BaseData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ BaseData.__init__(self, *args, **kwargs)
+ self.fstype = kwargs.get("fstype", "")
+ self.grow = kwargs.get("grow", False)
+ self.maxSizeMB = kwargs.get("maxSizeMB", 0)
+ self.name = kwargs.get("name", "")
+ self.format = kwargs.get("format", True)
+ self.percent = kwargs.get("percent", 0)
+ self.recommended = kwargs.get("recommended", False)
+ self.size = kwargs.get("size", None)
+ self.preexist = kwargs.get("preexist", False)
+ self.vgname = kwargs.get("vgname", "")
+ self.mountpoint = kwargs.get("mountpoint", "")
+
+ def __eq__(self, y):
+ return self.vgname == y.vgname and self.name == y.name
+
+ def _getArgsAsStr(self):
+ retval = ""
+
+ if self.fstype != "":
+ retval += " --fstype=\"%s\"" % self.fstype
+ if self.grow:
+ retval += " --grow"
+ if self.maxSizeMB > 0:
+ retval += " --maxsize=%d" % self.maxSizeMB
+ if not self.format:
+ retval += " --noformat"
+ if self.percent > 0:
+ retval += " --percent=%d" % self.percent
+ if self.recommended:
+ retval += " --recommended"
+ if self.size > 0:
+ retval += " --size=%d" % self.size
+ if self.preexist:
+ retval += " --useexisting"
+
+ return retval
+
+ def __str__(self):
+ retval = BaseData.__str__(self)
+ retval += "logvol %s %s --name=%s --vgname=%s\n" % (self.mountpoint, self._getArgsAsStr(), self.name, self.vgname)
+ return retval
+
+class FC4_LogVolData(FC3_LogVolData):
+ removedKeywords = FC3_LogVolData.removedKeywords
+ removedAttrs = FC3_LogVolData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ FC3_LogVolData.__init__(self, *args, **kwargs)
+ self.bytesPerInode = kwargs.get("bytesPerInode", 4096)
+ self.fsopts = kwargs.get("fsopts", "")
+
+ def _getArgsAsStr(self):
+ retval = FC3_LogVolData._getArgsAsStr(self)
+
+ if hasattr(self, "bytesPerInode") and self.bytesPerInode != 0:
+ retval += " --bytes-per-inode=%d" % self.bytesPerInode
+ if self.fsopts != "":
+ retval += " --fsoptions=\"%s\"" % self.fsopts
+
+ return retval
+
+class RHEL5_LogVolData(FC4_LogVolData):
+ removedKeywords = FC4_LogVolData.removedKeywords
+ removedAttrs = FC4_LogVolData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ FC4_LogVolData.__init__(self, *args, **kwargs)
+ self.encrypted = kwargs.get("encrypted", False)
+ self.passphrase = kwargs.get("passphrase", "")
+
+ def _getArgsAsStr(self):
+ retval = FC4_LogVolData._getArgsAsStr(self)
+
+ if self.encrypted:
+ retval += " --encrypted"
+
+ if self.passphrase != "":
+ retval += " --passphrase=\"%s\"" % self.passphrase
+
+ return retval
+
+class F9_LogVolData(FC4_LogVolData):
+ removedKeywords = FC4_LogVolData.removedKeywords + ["bytesPerInode"]
+ removedAttrs = FC4_LogVolData.removedAttrs + ["bytesPerInode"]
+
+ def __init__(self, *args, **kwargs):
+ FC4_LogVolData.__init__(self, *args, **kwargs)
+ self.deleteRemovedAttrs()
+
+ self.fsopts = kwargs.get("fsopts", "")
+ self.fsprofile = kwargs.get("fsprofile", "")
+ self.encrypted = kwargs.get("encrypted", False)
+ self.passphrase = kwargs.get("passphrase", "")
+
+ def _getArgsAsStr(self):
+ retval = FC4_LogVolData._getArgsAsStr(self)
+
+ if self.fsprofile != "":
+ retval += " --fsprofile=\"%s\"" % self.fsprofile
+ if self.encrypted:
+ retval += " --encrypted"
+
+ if self.passphrase != "":
+ retval += " --passphrase=\"%s\"" % self.passphrase
+
+ return retval
+
+class F12_LogVolData(F9_LogVolData):
+ removedKeywords = F9_LogVolData.removedKeywords
+ removedAttrs = F9_LogVolData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ F9_LogVolData.__init__(self, *args, **kwargs)
+ self.deleteRemovedAttrs()
+
+ self.escrowcert = kwargs.get("escrowcert", "")
+ self.backuppassphrase = kwargs.get("backuppassphrase", False)
+
+ def _getArgsAsStr(self):
+ retval = F9_LogVolData._getArgsAsStr(self)
+
+ if self.encrypted and self.escrowcert != "":
+ retval += " --escrowcert=\"%s\"" % self.escrowcert
+
+ if self.backuppassphrase:
+ retval += " --backuppassphrase"
+
+ return retval
+
+F14_LogVolData = F12_LogVolData
+
+class F15_LogVolData(F14_LogVolData):
+ removedKeywords = F14_LogVolData.removedKeywords
+ removedAttrs = F14_LogVolData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ F14_LogVolData.__init__(self, *args, **kwargs)
+ self.label = kwargs.get("label", "")
+
+ def _getArgsAsStr(self):
+ retval = F14_LogVolData._getArgsAsStr(self)
+
+ if self.label != "":
+ retval += " --label=\"%s\"" % self.label
+
+ return retval
+
+class FC3_LogVol(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=133, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.lvList = kwargs.get("lvList", [])
+
+ def __str__(self):
+ retval = ""
+
+ for part in self.lvList:
+ retval += part.__str__()
+
+ return retval
+
+ def _getParser(self):
+ def lv_cb (option, opt_str, value, parser):
+ parser.values.format = False
+ parser.values.preexist = True
+
+ op = KSOptionParser()
+ op.add_option("--fstype", dest="fstype")
+ op.add_option("--grow", dest="grow", action="store_true",
+ default=False)
+ op.add_option("--maxsize", dest="maxSizeMB", action="store", type="int",
+ nargs=1)
+ op.add_option("--name", dest="name", required=1)
+ op.add_option("--noformat", action="callback", callback=lv_cb,
+ dest="format", default=True, nargs=0)
+ op.add_option("--percent", dest="percent", action="store", type="int",
+ nargs=1)
+ op.add_option("--recommended", dest="recommended", action="store_true",
+ default=False)
+ op.add_option("--size", dest="size", action="store", type="int",
+ nargs=1)
+ op.add_option("--useexisting", dest="preexist", action="store_true",
+ default=False)
+ op.add_option("--vgname", dest="vgname", required=1)
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+
+ if len(extra) == 0:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Mount point required for %s") % "logvol"))
+
+ lvd = self.handler.LogVolData()
+ self._setToObj(self.op, opts, lvd)
+ lvd.lineno = self.lineno
+ lvd.mountpoint=extra[0]
+
+ # Check for duplicates in the data list.
+ if lvd in self.dataList():
+ warnings.warn(_("A logical volume with the name %s has already been defined in volume group %s.") % (lvd.device, lvd.vgname))
+
+ return lvd
+
+ def dataList(self):
+ return self.lvList
+
+class FC4_LogVol(FC3_LogVol):
+ removedKeywords = FC3_LogVol.removedKeywords
+ removedAttrs = FC3_LogVol.removedAttrs
+
+ def _getParser(self):
+ op = FC3_LogVol._getParser(self)
+ op.add_option("--bytes-per-inode", dest="bytesPerInode", action="store",
+ type="int", nargs=1)
+ op.add_option("--fsoptions", dest="fsopts")
+ return op
+
+class RHEL5_LogVol(FC4_LogVol):
+ removedKeywords = FC4_LogVol.removedKeywords
+ removedAttrs = FC4_LogVol.removedAttrs
+
+ def _getParser(self):
+ op = FC4_LogVol._getParser(self)
+ op.add_option("--encrypted", action="store_true", default=False)
+ op.add_option("--passphrase")
+ return op
+
+class F9_LogVol(FC4_LogVol):
+ removedKeywords = FC4_LogVol.removedKeywords
+ removedAttrs = FC4_LogVol.removedAttrs
+
+ def _getParser(self):
+ op = FC4_LogVol._getParser(self)
+ op.add_option("--bytes-per-inode", deprecated=1)
+ op.add_option("--fsprofile", dest="fsprofile", action="store",
+ type="string", nargs=1)
+ op.add_option("--encrypted", action="store_true", default=False)
+ op.add_option("--passphrase")
+ return op
+
+class F12_LogVol(F9_LogVol):
+ removedKeywords = F9_LogVol.removedKeywords
+ removedAttrs = F9_LogVol.removedAttrs
+
+ def _getParser(self):
+ op = F9_LogVol._getParser(self)
+ op.add_option("--escrowcert")
+ op.add_option("--backuppassphrase", action="store_true", default=False)
+ return op
+
+class F14_LogVol(F12_LogVol):
+ removedKeywords = F12_LogVol.removedKeywords
+ removedAttrs = F12_LogVol.removedAttrs
+
+ def _getParser(self):
+ op = F12_LogVol._getParser(self)
+ op.remove_option("--bytes-per-inode")
+ return op
+
+class F15_LogVol(F14_LogVol):
+ removedKeywords = F14_LogVol.removedKeywords
+ removedAttrs = F14_LogVol.removedAttrs
+
+ def _getParser(self):
+ op = F14_LogVol._getParser(self)
+ op.add_option("--label")
+ return op
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC4_MediaCheck(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+ self.mediacheck = kwargs.get("mediacheck", False)
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+ if self.mediacheck:
+ retval += "mediacheck\n"
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ if len(extra) > 0:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Kickstart command %s does not take any arguments") % "mediacheck"))
+
+ self.mediacheck = True
+ return self
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2007, 2009 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_Method(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.method = kwargs.get("method", "")
+
+ # Set all these attributes so calls to this command's __call__
+ # method can set them. However we don't want to provide them as
+ # arguments to __init__ because method is special.
+ self.biospart = None
+ self.partition = None
+ self.server = None
+ self.dir = None
+ self.url = None
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.method == "cdrom":
+ retval += "# Use CDROM installation media\ncdrom\n"
+ elif self.method == "harddrive":
+ msg = "# Use hard drive installation media\nharddrive --dir=%s" % self.dir
+
+ if self.biospart is not None:
+ retval += msg + " --biospart=%s\n" % self.biospart
+ else:
+ retval += msg + " --partition=%s\n" % self.partition
+ elif self.method == "nfs":
+ retval += "# Use NFS installation media\nnfs --server=%s --dir=%s\n" % (self.server, self.dir)
+ elif self.method == "url":
+ retval += "# Use network installation\nurl --url=\"%s\"\n" % self.url
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+
+ # method = "cdrom" falls through to the return
+ if self.currentCmd == "harddrive":
+ op.add_option("--biospart", dest="biospart")
+ op.add_option("--partition", dest="partition")
+ op.add_option("--dir", dest="dir", required=1)
+ elif self.currentCmd == "nfs":
+ op.add_option("--server", dest="server", required=1)
+ op.add_option("--dir", dest="dir", required=1)
+ elif self.currentCmd == "url":
+ op.add_option("--url", dest="url", required=1)
+
+ return op
+
+ def parse(self, args):
+ self.method = self.currentCmd
+
+ op = self._getParser()
+ (opts, extra) = op.parse_args(args=args, lineno=self.lineno)
+ self._setToSelf(op, opts)
+
+ if self.currentCmd == "harddrive":
+ if self.biospart is None and self.partition is None or \
+ self.biospart is not None and self.partition is not None:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("One of biospart or partition options must be specified.")))
+
+ return self
+
+class FC6_Method(FC3_Method):
+ removedKeywords = FC3_Method.removedKeywords
+ removedAttrs = FC3_Method.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ FC3_Method.__init__(self, writePriority, *args, **kwargs)
+
+ # Same reason for this attribute as the comment in FC3_Method.
+ self.opts = None
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.method == "cdrom":
+ retval += "# Use CDROM installation media\ncdrom\n"
+ elif self.method == "harddrive":
+ msg = "# Use hard drive installation media\nharddrive --dir=%s" % self.dir
+
+ if self.biospart is not None:
+ retval += msg + " --biospart=%s\n" % self.biospart
+ else:
+ retval += msg + " --partition=%s\n" % self.partition
+ elif self.method == "nfs":
+ retval += "# Use NFS installation media\nnfs --server=%s --dir=%s" % (self.server, self.dir)
+ if self.opts is not None:
+ retval += " --opts=\"%s\"" % self.opts
+ retval += "\n"
+ elif self.method == "url":
+ retval += "# Use network installation\nurl --url=\"%s\"\n" % self.url
+
+ return retval
+
+ def _getParser(self):
+ op = FC3_Method._getParser(self)
+
+ if self.currentCmd == "nfs":
+ op.add_option("--opts", dest="opts")
+
+ return op
+
+class F13_Method(FC6_Method):
+ removedKeywords = FC6_Method.removedKeywords
+ removedAttrs = FC6_Method.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ FC6_Method.__init__(self, *args, **kwargs)
+
+ # And same as all the other __init__ methods.
+ self.proxy = ""
+
+ def __str__(self):
+ retval = FC6_Method.__str__(self)
+
+ if self.method == "url" and self.proxy:
+ retval = retval.strip()
+ retval += " --proxy=\"%s\"\n" % self.proxy
+
+ return retval
+
+ def _getParser(self):
+ op = FC6_Method._getParser(self)
+
+ if self.currentCmd == "url":
+ op.add_option("--proxy")
+
+ return op
+
+class F14_Method(F13_Method):
+ removedKeywords = F13_Method.removedKeywords
+ removedAttrs = F13_Method.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ F13_Method.__init__(self, *args, **kwargs)
+
+ self.noverifyssl = False
+
+ def __str__(self):
+ retval = F13_Method.__str__(self)
+
+ if self.method == "url" and self.noverifyssl:
+ retval = retval.strip()
+ retval += " --noverifyssl\n"
+
+ return retval
+
+ def _getParser(self):
+ op = F13_Method._getParser(self)
+
+ if self.currentCmd == "url":
+ op.add_option("--noverifyssl", action="store_true", default=False)
+
+ return op
+
+RHEL6_Method = F14_Method
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007, 2008 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_Monitor(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.hsync = kwargs.get("hsync", "")
+ self.monitor = kwargs.get("monitor", "")
+ self.vsync = kwargs.get("vsync", "")
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+ retval += "monitor"
+
+ if self.hsync != "":
+ retval += " --hsync=%s" % self.hsync
+ if self.monitor != "":
+ retval += " --monitor=\"%s\"" % self.monitor
+ if self.vsync != "":
+ retval += " --vsync=%s" % self.vsync
+
+ if retval != "monitor":
+ return retval + "\n"
+ else:
+ return ""
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--hsync")
+ op.add_option("--monitor")
+ op.add_option("--vsync")
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+
+ if extra:
+ mapping = {"cmd": "monitor", "options": extra}
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Unexpected arguments to %(cmd)s command: %(options)s") % mapping))
+
+ self._setToSelf(self.op, opts)
+ return self
+
+class FC6_Monitor(FC3_Monitor):
+ removedKeywords = FC3_Monitor.removedKeywords
+ removedAttrs = FC3_Monitor.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ FC3_Monitor.__init__(self, writePriority, *args, **kwargs)
+ self.probe = kwargs.get("probe", True)
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+ retval += "monitor"
+
+ if self.hsync != "":
+ retval += " --hsync=%s" % self.hsync
+ if self.monitor != "":
+ retval += " --monitor=\"%s\"" % self.monitor
+ if not self.probe:
+ retval += " --noprobe"
+ if self.vsync != "":
+ retval += " --vsync=%s" % self.vsync
+
+ if retval != "monitor":
+ return retval + "\n"
+ else:
+ return ""
+
+ def _getParser(self):
+ op = FC3_Monitor._getParser(self)
+ op.add_option("--noprobe", dest="probe", action="store_false",
+ default=True)
+ return op
+
+class F10_Monitor(DeprecatedCommand):
+ def __init__(self):
+ DeprecatedCommand.__init__(self)
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class RHEL3_Mouse(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.device = kwargs.get("device", "")
+ self.emulthree = kwargs.get("emulthree", False)
+ self.mouse = kwargs.get("mouse", "")
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ opts = ""
+ if self.device:
+ opts += "--device=%s " % self.device
+ if self.emulthree:
+ opts += "--emulthree "
+
+ if self.mouse:
+ retval += "# System mouse\nmouse %s%s\n" % (opts, self.mouse)
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--device", dest="device", default="")
+ op.add_option("--emulthree", dest="emulthree", default=False, action="store_true")
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ self._setToSelf(self.op, opts)
+
+ if len(extra) != 1:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Kickstart command %s requires one argument") % "mouse"))
+
+ self.mouse = extra[0]
+ return self
+
+class FC3_Mouse(DeprecatedCommand):
+ def __init__(self):
+ DeprecatedCommand.__init__(self)
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+# Peter Jones <pjones@redhat.com>
+#
+# Copyright 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC6_MpPathData(BaseData):
+ removedKeywords = BaseData.removedKeywords
+ removedAttrs = BaseData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ BaseData.__init__(self, *args, **kwargs)
+ self.mpdev = kwargs.get("mpdev", "")
+ self.device = kwargs.get("device", "")
+ self.rule = kwargs.get("rule", "")
+
+ def __str__(self):
+ return " --device=%s --rule=\"%s\"" % (self.device, self.rule)
+
+class FC6_MultiPathData(BaseData):
+ removedKeywords = BaseData.removedKeywords
+ removedAttrs = BaseData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ BaseData.__init__(self, *args, **kwargs)
+ self.name = kwargs.get("name", "")
+ self.paths = kwargs.get("paths", [])
+
+ def __str__(self):
+ retval = BaseData.__str__(self)
+
+ for path in self.paths:
+ retval += "multipath --mpdev=%s %s\n" % (self.name, path.__str__())
+
+ return retval
+
+class FC6_MultiPath(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=50, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.mpaths = kwargs.get("mpaths", [])
+
+ def __str__(self):
+ retval = ""
+ for mpath in self.mpaths:
+ retval += mpath.__str__()
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--name", dest="name", action="store", type="string",
+ required=1)
+ op.add_option("--device", dest="device", action="store", type="string",
+ required=1)
+ op.add_option("--rule", dest="rule", action="store", type="string",
+ required=1)
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ dd = FC6_MpPathData()
+ self._setToObj(self.op, opts, dd)
+ dd.lineno = self.lineno
+ dd.mpdev = dd.mpdev.split('/')[-1]
+
+ parent = None
+ for x in range(0, len(self.mpaths)):
+ mpath = self.mpaths[x]
+ for path in mpath.paths:
+ if path.device == dd.device:
+ mapping = {"device": path.device, "multipathdev": path.mpdev}
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Device '%(device)s' is already used in multipath '%(multipathdev)s'") % mapping))
+ if mpath.name == dd.mpdev:
+ parent = x
+
+ if parent is None:
+ mpath = FC6_MultiPathData()
+ return mpath
+ else:
+ mpath = self.mpaths[parent]
+
+ return dd
+
+ def dataList(self):
+ return self.mpaths
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007, 2008 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.constants import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+import warnings
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_NetworkData(BaseData):
+ removedKeywords = BaseData.removedKeywords
+ removedAttrs = BaseData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ BaseData.__init__(self, *args, **kwargs)
+ self.bootProto = kwargs.get("bootProto", BOOTPROTO_DHCP)
+ self.dhcpclass = kwargs.get("dhcpclass", "")
+ self.device = kwargs.get("device", "")
+ self.essid = kwargs.get("essid", "")
+ self.ethtool = kwargs.get("ethtool", "")
+ self.gateway = kwargs.get("gateway", "")
+ self.hostname = kwargs.get("hostname", "")
+ self.ip = kwargs.get("ip", "")
+ self.mtu = kwargs.get("mtu", "")
+ self.nameserver = kwargs.get("nameserver", "")
+ self.netmask = kwargs.get("netmask", "")
+ self.nodns = kwargs.get("nodns", False)
+ self.onboot = kwargs.get("onboot", True)
+ self.wepkey = kwargs.get("wepkey", "")
+
+ def __eq__(self, y):
+ return self.device and self.device == y.device
+
+ def _getArgsAsStr(self):
+ retval = ""
+
+ if self.bootProto != "":
+ retval += " --bootproto=%s" % self.bootProto
+ if self.dhcpclass != "":
+ retval += " --dhcpclass=%s" % self.dhcpclass
+ if self.device != "":
+ retval += " --device=%s" % self.device
+ if self.essid != "":
+ retval += " --essid=\"%s\"" % self.essid
+ if self.ethtool != "":
+ retval += " --ethtool=\"%s\"" % self.ethtool
+ if self.gateway != "":
+ retval += " --gateway=%s" % self.gateway
+ if self.hostname != "":
+ retval += " --hostname=%s" % self.hostname
+ if self.ip != "":
+ retval += " --ip=%s" % self.ip
+ if self.mtu != "":
+ retval += " --mtu=%s" % self.mtu
+ if self.nameserver != "":
+ retval += " --nameserver=%s" % self.nameserver
+ if self.netmask != "":
+ retval += " --netmask=%s" % self.netmask
+ if self.nodns:
+ retval += " --nodns"
+ if not self.onboot:
+ retval += " --onboot=off"
+ if self.wepkey != "":
+ retval += " --wepkey=%s" % self.wepkey
+
+ return retval
+
+ def __str__(self):
+ retval = BaseData.__str__(self)
+ retval += "network %s\n" % self._getArgsAsStr()
+ return retval
+
+class FC4_NetworkData(FC3_NetworkData):
+ removedKeywords = FC3_NetworkData.removedKeywords
+ removedAttrs = FC3_NetworkData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ FC3_NetworkData.__init__(self, *args, **kwargs)
+ self.notksdevice = kwargs.get("notksdevice", False)
+
+ def _getArgsAsStr(self):
+ retval = FC3_NetworkData._getArgsAsStr(self)
+
+ if self.notksdevice:
+ retval += " --notksdevice"
+
+ return retval
+
+class FC6_NetworkData(FC4_NetworkData):
+ removedKeywords = FC4_NetworkData.removedKeywords
+ removedAttrs = FC4_NetworkData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ FC4_NetworkData.__init__(self, *args, **kwargs)
+ self.noipv4 = kwargs.get("noipv4", False)
+ self.noipv6 = kwargs.get("noipv6", False)
+
+ def _getArgsAsStr(self):
+ retval = FC4_NetworkData._getArgsAsStr(self)
+
+ if self.noipv4:
+ retval += " --noipv4"
+ if self.noipv6:
+ retval += " --noipv6"
+
+ return retval
+
+class F8_NetworkData(FC6_NetworkData):
+ removedKeywords = FC6_NetworkData.removedKeywords
+ removedAttrs = FC6_NetworkData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ FC6_NetworkData.__init__(self, *args, **kwargs)
+ self.ipv6 = kwargs.get("ipv6", "")
+
+ def _getArgsAsStr(self):
+ retval = FC6_NetworkData._getArgsAsStr(self)
+
+ if self.ipv6 != "":
+ retval += " --ipv6" % self.ipv6
+
+ return retval
+
+class F16_NetworkData(F8_NetworkData):
+ removedKeywords = F8_NetworkData.removedKeywords
+ removedAttrs = F8_NetworkData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ F8_NetworkData.__init__(self, *args, **kwargs)
+ self.activate = kwargs.get("activate", False)
+ self.nodefroute = kwargs.get("nodefroute", False)
+ self.wpakey = kwargs.get("wpakey", "")
+
+ def _getArgsAsStr(self):
+ retval = F8_NetworkData._getArgsAsStr(self)
+
+ if self.activate:
+ retval += " --activate"
+ if self.nodefroute:
+ retval += " --nodefroute"
+ if self.wpakey != "":
+ retval += "--wpakey=%s" % self.wpakey
+
+ return retval
+
+class RHEL4_NetworkData(FC3_NetworkData):
+ removedKeywords = FC3_NetworkData.removedKeywords
+ removedAttrs = FC3_NetworkData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ FC3_NetworkData.__init__(self, *args, **kwargs)
+ self.notksdevice = kwargs.get("notksdevice", False)
+
+ def _getArgsAsStr(self):
+ retval = FC3_NetworkData._getArgsAsStr(self)
+
+ if self.notksdevice:
+ retval += " --notksdevice"
+
+ return retval
+
+class RHEL6_NetworkData(F8_NetworkData):
+ removedKeywords = F8_NetworkData.removedKeywords
+ removedAttrs = F8_NetworkData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ F8_NetworkData.__init__(self, *args, **kwargs)
+ self.activate = kwargs.get("activate", False)
+ self.nodefroute = kwargs.get("nodefroute", False)
+
+ def _getArgsAsStr(self):
+ retval = F8_NetworkData._getArgsAsStr(self)
+
+ if self.activate:
+ retval += " --activate"
+ if self.nodefroute:
+ retval += " --nodefroute"
+
+ return retval
+
+class FC3_Network(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.bootprotoList = [BOOTPROTO_DHCP, BOOTPROTO_BOOTP,
+ BOOTPROTO_STATIC]
+
+ self.op = self._getParser()
+
+ self.network = kwargs.get("network", [])
+
+ def __str__(self):
+ retval = ""
+
+ for nic in self.network:
+ retval += nic.__str__()
+
+ if retval != "":
+ return "# Network information\n" + retval
+ else:
+ return ""
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--bootproto", dest="bootProto",
+ default=BOOTPROTO_DHCP,
+ choices=self.bootprotoList)
+ op.add_option("--dhcpclass", dest="dhcpclass")
+ op.add_option("--device", dest="device")
+ op.add_option("--essid", dest="essid")
+ op.add_option("--ethtool", dest="ethtool")
+ op.add_option("--gateway", dest="gateway")
+ op.add_option("--hostname", dest="hostname")
+ op.add_option("--ip", dest="ip")
+ op.add_option("--mtu", dest="mtu")
+ op.add_option("--nameserver", dest="nameserver")
+ op.add_option("--netmask", dest="netmask")
+ op.add_option("--nodns", dest="nodns", action="store_true",
+ default=False)
+ op.add_option("--onboot", dest="onboot", action="store",
+ type="ksboolean")
+ op.add_option("--wepkey", dest="wepkey")
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ nd = self.handler.NetworkData()
+ self._setToObj(self.op, opts, nd)
+ nd.lineno = self.lineno
+
+ # Check for duplicates in the data list.
+ if nd in self.dataList():
+ warnings.warn(_("A network device with the name %s has already been defined.") % nd.device)
+
+ return nd
+
+ def dataList(self):
+ return self.network
+
+class FC4_Network(FC3_Network):
+ removedKeywords = FC3_Network.removedKeywords
+ removedAttrs = FC3_Network.removedAttrs
+
+ def _getParser(self):
+ op = FC3_Network._getParser(self)
+ op.add_option("--notksdevice", dest="notksdevice", action="store_true",
+ default=False)
+ return op
+
+class FC6_Network(FC4_Network):
+ removedKeywords = FC4_Network.removedKeywords
+ removedAttrs = FC4_Network.removedAttrs
+
+ def _getParser(self):
+ op = FC4_Network._getParser(self)
+ op.add_option("--noipv4", dest="noipv4", action="store_true",
+ default=False)
+ op.add_option("--noipv6", dest="noipv6", action="store_true",
+ default=False)
+ return op
+
+class F8_Network(FC6_Network):
+ removedKeywords = FC6_Network.removedKeywords
+ removedAttrs = FC6_Network.removedAttrs
+
+ def _getParser(self):
+ op = FC6_Network._getParser(self)
+ op.add_option("--ipv6", dest="ipv6")
+ return op
+
+class F9_Network(F8_Network):
+ removedKeywords = F8_Network.removedKeywords
+ removedAttrs = F8_Network.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ F8_Network.__init__(self, writePriority, *args, **kwargs)
+ self.bootprotoList.append(BOOTPROTO_QUERY)
+
+ def _getParser(self):
+ op = F8_Network._getParser(self)
+ op.add_option("--bootproto", dest="bootProto",
+ default=BOOTPROTO_DHCP,
+ choices=self.bootprotoList)
+ return op
+
+class F16_Network(F9_Network):
+ removedKeywords = F9_Network.removedKeywords
+ removedAttrs = F9_Network.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ F9_Network.__init__(self, writePriority, *args, **kwargs)
+ self.bootprotoList.append(BOOTPROTO_IBFT)
+
+ def _getParser(self):
+ op = F9_Network._getParser(self)
+ op.add_option("--activate", dest="activate", action="store_true",
+ default=False)
+ op.add_option("--nodefroute", dest="nodefroute", action="store_true",
+ default=False)
+ op.add_option("--wpakey", dest="wpakey", action="store", default="")
+ return op
+
+class RHEL4_Network(FC3_Network):
+ removedKeywords = FC3_Network.removedKeywords
+ removedAttrs = FC3_Network.removedAttrs
+
+ def _getParser(self):
+ op = FC3_Network._getParser(self)
+ op.add_option("--notksdevice", dest="notksdevice", action="store_true",
+ default=False)
+ return op
+
+class RHEL5_Network(FC6_Network):
+ removedKeywords = FC6_Network.removedKeywords
+ removedAttrs = FC6_Network.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ FC6_Network.__init__(self, writePriority, *args, **kwargs)
+ self.bootprotoList.append(BOOTPROTO_QUERY)
+
+ def _getParser(self):
+ op = FC6_Network._getParser(self)
+ op.add_option("--bootproto", dest="bootProto",
+ default=BOOTPROTO_DHCP,
+ choices=self.bootprotoList)
+ return op
+
+class RHEL6_Network(F9_Network):
+ removedKeywords = F9_Network.removedKeywords
+ removedAttrs = F9_Network.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ F9_Network.__init__(self, writePriority, *args, **kwargs)
+ self.bootprotoList.append(BOOTPROTO_IBFT)
+
+ def _getParser(self):
+ op = F9_Network._getParser(self)
+ op.add_option("--activate", dest="activate", action="store_true",
+ default=False)
+ op.add_option("--nodefroute", dest="nodefroute", action="store_true",
+ default=False)
+ return op
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007, 2008 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+import warnings
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_PartData(BaseData):
+ removedKeywords = BaseData.removedKeywords
+ removedAttrs = BaseData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ BaseData.__init__(self, *args, **kwargs)
+ self.active = kwargs.get("active", False)
+ self.primOnly = kwargs.get("primOnly", False)
+ self.end = kwargs.get("end", 0)
+ self.fstype = kwargs.get("fstype", "")
+ self.grow = kwargs.get("grow", False)
+ self.maxSizeMB = kwargs.get("maxSizeMB", 0)
+ self.format = kwargs.get("format", True)
+ self.onbiosdisk = kwargs.get("onbiosdisk", "")
+ self.disk = kwargs.get("disk", "")
+ self.onPart = kwargs.get("onPart", "")
+ self.recommended = kwargs.get("recommended", False)
+ self.size = kwargs.get("size", None)
+ self.start = kwargs.get("start", 0)
+ self.mountpoint = kwargs.get("mountpoint", "")
+
+ def __eq__(self, y):
+ if self.mountpoint:
+ return self.mountpoint == y.mountpoint
+ else:
+ return False
+
+ def _getArgsAsStr(self):
+ retval = ""
+
+ if self.active:
+ retval += " --active"
+ if self.primOnly:
+ retval += " --asprimary"
+ if hasattr(self, "end") and self.end != 0:
+ retval += " --end=%s" % self.end
+ if self.fstype != "":
+ retval += " --fstype=\"%s\"" % self.fstype
+ if self.grow:
+ retval += " --grow"
+ if self.maxSizeMB > 0:
+ retval += " --maxsize=%d" % self.maxSizeMB
+ if not self.format:
+ retval += " --noformat"
+ if self.onbiosdisk != "":
+ retval += " --onbiosdisk=%s" % self.onbiosdisk
+ if self.disk != "":
+ retval += " --ondisk=%s" % self.disk
+ if self.onPart != "":
+ retval += " --onpart=%s" % self.onPart
+ if self.recommended:
+ retval += " --recommended"
+ if self.size and self.size != 0:
+ retval += " --size=%s" % self.size
+ if hasattr(self, "start") and self.start != 0:
+ retval += " --start=%s" % self.start
+
+ return retval
+
+ def __str__(self):
+ retval = BaseData.__str__(self)
+ if self.mountpoint:
+ mountpoint_str = "%s" % self.mountpoint
+ else:
+ mountpoint_str = "(No mount point)"
+ retval += "part %s%s\n" % (mountpoint_str, self._getArgsAsStr())
+ return retval
+
+class FC4_PartData(FC3_PartData):
+ removedKeywords = FC3_PartData.removedKeywords
+ removedAttrs = FC3_PartData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ FC3_PartData.__init__(self, *args, **kwargs)
+ 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)
+
+ if hasattr(self, "bytesPerInode") and self.bytesPerInode != 0:
+ retval += " --bytes-per-inode=%d" % self.bytesPerInode
+ if self.fsopts != "":
+ retval += " --fsoptions=\"%s\"" % self.fsopts
+ if self.label != "":
+ retval += " --label=%s" % self.label
+ if self.fslabel != "":
+ retval += " --fslabel=%s" % self.fslabel
+
+ return retval
+
+class RHEL5_PartData(FC4_PartData):
+ removedKeywords = FC4_PartData.removedKeywords
+ removedAttrs = FC4_PartData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ FC4_PartData.__init__(self, *args, **kwargs)
+ self.encrypted = kwargs.get("encrypted", False)
+ self.passphrase = kwargs.get("passphrase", "")
+
+ def _getArgsAsStr(self):
+ retval = FC4_PartData._getArgsAsStr(self)
+
+ if self.encrypted:
+ retval += " --encrypted"
+
+ if self.passphrase != "":
+ retval += " --passphrase=\"%s\"" % self.passphrase
+
+ return retval
+
+class F9_PartData(FC4_PartData):
+ removedKeywords = FC4_PartData.removedKeywords + ["bytesPerInode"]
+ removedAttrs = FC4_PartData.removedAttrs + ["bytesPerInode"]
+
+ def __init__(self, *args, **kwargs):
+ FC4_PartData.__init__(self, *args, **kwargs)
+ self.deleteRemovedAttrs()
+
+ self.fsopts = kwargs.get("fsopts", "")
+ self.label = kwargs.get("label", "")
+ self.fsprofile = kwargs.get("fsprofile", "")
+ self.encrypted = kwargs.get("encrypted", False)
+ self.passphrase = kwargs.get("passphrase", "")
+
+ def _getArgsAsStr(self):
+ retval = FC4_PartData._getArgsAsStr(self)
+
+ if self.fsprofile != "":
+ retval += " --fsprofile=\"%s\"" % self.fsprofile
+ if self.encrypted:
+ retval += " --encrypted"
+
+ if self.passphrase != "":
+ retval += " --passphrase=\"%s\"" % self.passphrase
+
+ return retval
+
+class F11_PartData(F9_PartData):
+ removedKeywords = F9_PartData.removedKeywords + ["start", "end"]
+ removedAttrs = F9_PartData.removedAttrs + ["start", "end"]
+
+class F12_PartData(F11_PartData):
+ removedKeywords = F11_PartData.removedKeywords
+ removedAttrs = F11_PartData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ F11_PartData.__init__(self, *args, **kwargs)
+
+ self.escrowcert = kwargs.get("escrowcert", "")
+ self.backuppassphrase = kwargs.get("backuppassphrase", False)
+
+ def _getArgsAsStr(self):
+ retval = F11_PartData._getArgsAsStr(self)
+
+ if self.encrypted and self.escrowcert != "":
+ retval += " --escrowcert=\"%s\"" % self.escrowcert
+
+ if self.backuppassphrase:
+ retval += " --backuppassphrase"
+
+ return retval
+
+F14_PartData = F12_PartData
+
+class FC3_Partition(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=130, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.partitions = kwargs.get("partitions", [])
+
+ def __str__(self):
+ retval = ""
+
+ for part in self.partitions:
+ retval += part.__str__()
+
+ if retval != "":
+ return "# Disk partitioning information\n" + retval
+ else:
+ return ""
+
+ def _getParser(self):
+ def part_cb (option, opt_str, value, parser):
+ if value.startswith("/dev/"):
+ parser.values.ensure_value(option.dest, value[5:])
+ else:
+ parser.values.ensure_value(option.dest, value)
+
+ op = KSOptionParser()
+ op.add_option("--active", dest="active", action="store_true",
+ default=False)
+ op.add_option("--asprimary", dest="primOnly", action="store_true",
+ default=False)
+ op.add_option("--end", dest="end", action="store", type="int",
+ nargs=1)
+ op.add_option("--fstype", "--type", dest="fstype")
+ op.add_option("--grow", dest="grow", action="store_true", default=False)
+ op.add_option("--maxsize", dest="maxSizeMB", action="store", type="int",
+ nargs=1)
+ op.add_option("--noformat", dest="format", action="store_false",
+ default=True)
+ op.add_option("--onbiosdisk", dest="onbiosdisk")
+ op.add_option("--ondisk", "--ondrive", dest="disk")
+ op.add_option("--onpart", "--usepart", dest="onPart", action="callback",
+ callback=part_cb, nargs=1, type="string")
+ op.add_option("--recommended", dest="recommended", action="store_true",
+ default=False)
+ op.add_option("--size", dest="size", action="store", type="int",
+ nargs=1)
+ op.add_option("--start", dest="start", action="store", type="int",
+ nargs=1)
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+
+ pd = self.handler.PartData()
+ self._setToObj(self.op, opts, pd)
+ pd.lineno = self.lineno
+ if extra:
+ pd.mountpoint = extra[0]
+ if pd in self.dataList():
+ warnings.warn(_("A partition with the mountpoint %s has already been defined.") % pd.mountpoint)
+ else:
+ pd.mountpoint = None
+
+ return pd
+
+ def dataList(self):
+ return self.partitions
+
+class FC4_Partition(FC3_Partition):
+ removedKeywords = FC3_Partition.removedKeywords
+ removedAttrs = FC3_Partition.removedAttrs
+
+ def __init__(self, writePriority=130, *args, **kwargs):
+ FC3_Partition.__init__(self, writePriority, *args, **kwargs)
+
+ def part_cb (option, opt_str, value, parser):
+ if value.startswith("/dev/"):
+ parser.values.ensure_value(option.dest, value[5:])
+ else:
+ parser.values.ensure_value(option.dest, value)
+
+ def _getParser(self):
+ op = FC3_Partition._getParser(self)
+ op.add_option("--bytes-per-inode", dest="bytesPerInode", action="store",
+ 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):
+ removedKeywords = FC4_Partition.removedKeywords
+ removedAttrs = FC4_Partition.removedAttrs
+
+ def __init__(self, writePriority=130, *args, **kwargs):
+ FC4_Partition.__init__(self, writePriority, *args, **kwargs)
+
+ def part_cb (option, opt_str, value, parser):
+ if value.startswith("/dev/"):
+ parser.values.ensure_value(option.dest, value[5:])
+ else:
+ parser.values.ensure_value(option.dest, value)
+
+ def _getParser(self):
+ op = FC4_Partition._getParser(self)
+ op.add_option("--encrypted", action="store_true", default=False)
+ op.add_option("--passphrase")
+ return op
+
+class F9_Partition(FC4_Partition):
+ removedKeywords = FC4_Partition.removedKeywords
+ removedAttrs = FC4_Partition.removedAttrs
+
+ def __init__(self, writePriority=130, *args, **kwargs):
+ FC4_Partition.__init__(self, writePriority, *args, **kwargs)
+
+ def part_cb (option, opt_str, value, parser):
+ if value.startswith("/dev/"):
+ parser.values.ensure_value(option.dest, value[5:])
+ else:
+ parser.values.ensure_value(option.dest, value)
+
+ def _getParser(self):
+ op = FC4_Partition._getParser(self)
+ op.add_option("--bytes-per-inode", deprecated=1)
+ op.add_option("--fsprofile")
+ op.add_option("--encrypted", action="store_true", default=False)
+ op.add_option("--passphrase")
+ return op
+
+class F11_Partition(F9_Partition):
+ removedKeywords = F9_Partition.removedKeywords
+ removedAttrs = F9_Partition.removedAttrs
+
+ def _getParser(self):
+ op = F9_Partition._getParser(self)
+ op.add_option("--start", deprecated=1)
+ op.add_option("--end", deprecated=1)
+ return op
+
+class F12_Partition(F11_Partition):
+ removedKeywords = F11_Partition.removedKeywords
+ removedAttrs = F11_Partition.removedAttrs
+
+ def _getParser(self):
+ op = F11_Partition._getParser(self)
+ op.add_option("--escrowcert")
+ op.add_option("--backuppassphrase", action="store_true", default=False)
+ return op
+
+class F14_Partition(F12_Partition):
+ removedKeywords = F12_Partition.removedKeywords
+ removedAttrs = F12_Partition.removedAttrs
+
+ def _getParser(self):
+ op = F12_Partition._getParser(self)
+ op.remove_option("--bytes-per-inode")
+ op.remove_option("--start")
+ op.remove_option("--end")
+ return op
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007, 2008, 2011 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+import warnings
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_RaidData(BaseData):
+ removedKeywords = BaseData.removedKeywords
+ removedAttrs = BaseData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ BaseData.__init__(self, *args, **kwargs)
+ self.device = kwargs.get("device", None)
+ self.fstype = kwargs.get("fstype", "")
+ self.level = kwargs.get("level", "")
+ self.format = kwargs.get("format", True)
+ self.spares = kwargs.get("spares", 0)
+ self.preexist = kwargs.get("preexist", False)
+ self.mountpoint = kwargs.get("mountpoint", "")
+ self.members = kwargs.get("members", [])
+
+ def __eq__(self, y):
+ return self.device == y.device
+
+ def _getArgsAsStr(self):
+ retval = ""
+
+ if self.device != "":
+ retval += " --device=%s" % self.device
+ if self.fstype != "":
+ retval += " --fstype=\"%s\"" % self.fstype
+ if self.level != "":
+ retval += " --level=%s" % self.level
+ if not self.format:
+ retval += " --noformat"
+ if self.spares != 0:
+ retval += " --spares=%d" % self.spares
+ if self.preexist:
+ retval += " --useexisting"
+
+ return retval
+
+ def __str__(self):
+ retval = BaseData.__str__(self)
+ retval += "raid %s%s %s\n" % (self.mountpoint, self._getArgsAsStr(),
+ " ".join(self.members))
+ return retval
+
+class FC4_RaidData(FC3_RaidData):
+ removedKeywords = FC3_RaidData.removedKeywords
+ removedAttrs = FC3_RaidData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ FC3_RaidData.__init__(self, *args, **kwargs)
+ self.fsopts = kwargs.get("fsopts", "")
+
+ def _getArgsAsStr(self):
+ retval = FC3_RaidData._getArgsAsStr(self)
+
+ if self.fsopts != "":
+ retval += " --fsoptions=\"%s\"" % self.fsopts
+
+ return retval
+
+class FC5_RaidData(FC4_RaidData):
+ removedKeywords = FC4_RaidData.removedKeywords
+ removedAttrs = FC4_RaidData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ FC4_RaidData.__init__(self, *args, **kwargs)
+ self.bytesPerInode = kwargs.get("bytesPerInode", 4096)
+
+ def _getArgsAsStr(self):
+ retval = FC4_RaidData._getArgsAsStr(self)
+
+ if hasattr(self, "bytesPerInode") and self.bytesPerInode != 0:
+ retval += " --bytes-per-inode=%d" % self.bytesPerInode
+
+ return retval
+
+class RHEL5_RaidData(FC5_RaidData):
+ removedKeywords = FC5_RaidData.removedKeywords
+ removedAttrs = FC5_RaidData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ FC5_RaidData.__init__(self, *args, **kwargs)
+ self.encrypted = kwargs.get("encrypted", False)
+ self.passphrase = kwargs.get("passphrase", "")
+
+ def _getArgsAsStr(self):
+ retval = FC5_RaidData._getArgsAsStr(self)
+
+ if self.encrypted:
+ retval += " --encrypted"
+
+ if self.passphrase != "":
+ retval += " --passphrase=\"%s\"" % self.passphrase
+
+ return retval
+
+F7_RaidData = FC5_RaidData
+
+class F9_RaidData(FC5_RaidData):
+ removedKeywords = FC5_RaidData.removedKeywords + ["bytesPerInode"]
+ removedAttrs = FC5_RaidData.removedAttrs + ["bytesPerInode"]
+
+ def __init__(self, *args, **kwargs):
+ FC5_RaidData.__init__(self, *args, **kwargs)
+ self.deleteRemovedAttrs()
+
+ self.fsprofile = kwargs.get("fsprofile", "")
+ self.encrypted = kwargs.get("encrypted", False)
+ self.passphrase = kwargs.get("passphrase", "")
+
+ def _getArgsAsStr(self):
+ retval = FC5_RaidData._getArgsAsStr(self)
+
+ if self.fsprofile != "":
+ retval += " --fsprofile=\"%s\"" % self.fsprofile
+ if self.encrypted:
+ retval += " --encrypted"
+
+ if self.passphrase != "":
+ retval += " --passphrase=\"%s\"" % self.passphrase
+
+ return retval
+
+class F12_RaidData(F9_RaidData):
+ removedKeywords = F9_RaidData.removedKeywords
+ removedAttrs = F9_RaidData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ F9_RaidData.__init__(self, *args, **kwargs)
+ self.deleteRemovedAttrs()
+
+ self.escrowcert = kwargs.get("escrowcert", "")
+ self.backuppassphrase = kwargs.get("backuppassphrase", False)
+
+ def _getArgsAsStr(self):
+ retval = F9_RaidData._getArgsAsStr(self)
+
+ if self.encrypted and self.escrowcert != "":
+ retval += " --escrowcert=\"%s\"" % self.escrowcert
+
+ if self.backuppassphrase:
+ retval += " --backuppassphrase"
+ return retval
+
+F13_RaidData = F12_RaidData
+
+F14_RaidData = F13_RaidData
+
+class F15_RaidData(F14_RaidData):
+ removedKeywords = F14_RaidData.removedKeywords
+ removedAttrs = F14_RaidData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ F14_RaidData.__init__(self, *args, **kwargs)
+ self.deleteRemovedAttrs()
+
+ self.label = kwargs.get("label", "")
+
+ def _getArgsAsStr(self):
+ retval = F14_RaidData._getArgsAsStr(self)
+
+ if self.label != "":
+ retval += " --label=%s" % self.label
+
+ return retval
+
+class FC3_Raid(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=131, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ # A dict of all the RAID levels we support. This means that if we
+ # support more levels in the future, subclasses don't have to
+ # duplicate too much.
+ self.levelMap = { "RAID0": "RAID0", "0": "RAID0",
+ "RAID1": "RAID1", "1": "RAID1",
+ "RAID5": "RAID5", "5": "RAID5",
+ "RAID6": "RAID6", "6": "RAID6" }
+
+ self.raidList = kwargs.get("raidList", [])
+
+ def __str__(self):
+ retval = ""
+
+ for raid in self.raidList:
+ retval += raid.__str__()
+
+ return retval
+
+ def _getParser(self):
+ def raid_cb (option, opt_str, value, parser):
+ parser.values.format = False
+ parser.values.preexist = True
+
+ def device_cb (option, opt_str, value, parser):
+ if value[0:2] == "md":
+ parser.values.ensure_value(option.dest, value[2:])
+ else:
+ parser.values.ensure_value(option.dest, value)
+
+ def level_cb (option, opt_str, value, parser):
+ if self.levelMap.has_key(value):
+ parser.values.ensure_value(option.dest, self.levelMap[value])
+
+ op = KSOptionParser()
+ op.add_option("--device", action="callback", callback=device_cb,
+ dest="device", type="string", nargs=1, required=1)
+ op.add_option("--fstype", dest="fstype")
+ op.add_option("--level", dest="level", action="callback",
+ callback=level_cb, type="string", nargs=1)
+ op.add_option("--noformat", action="callback", callback=raid_cb,
+ dest="format", default=True, nargs=0)
+ op.add_option("--spares", dest="spares", action="store", type="int",
+ nargs=1, default=0)
+ op.add_option("--useexisting", dest="preexist", action="store_true",
+ default=False)
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+
+ if len(extra) == 0:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Mount point required for %s") % "raid"))
+ if len(extra) == 1:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Partitions required for %s") % "raid"))
+
+ rd = self.handler.RaidData()
+ self._setToObj(self.op, opts, rd)
+ rd.lineno = self.lineno
+
+ # --device can't just take an int in the callback above, because it
+ # could be specificed as "mdX", which causes optparse to error when
+ # it runs int().
+ rd.device = int(rd.device)
+ rd.mountpoint = extra[0]
+ rd.members = extra[1:]
+
+ # Check for duplicates in the data list.
+ if rd in self.dataList():
+ warnings.warn(_("A RAID device with the name %s has already been defined.") % rd.device)
+
+ return rd
+
+ def dataList(self):
+ return self.raidList
+
+class FC4_Raid(FC3_Raid):
+ removedKeywords = FC3_Raid.removedKeywords
+ removedAttrs = FC3_Raid.removedAttrs
+
+ def _getParser(self):
+ op = FC3_Raid._getParser(self)
+ op.add_option("--fsoptions", dest="fsopts")
+ return op
+
+class FC5_Raid(FC4_Raid):
+ removedKeywords = FC4_Raid.removedKeywords
+ removedAttrs = FC4_Raid.removedAttrs
+
+ def _getParser(self):
+ op = FC4_Raid._getParser(self)
+ op.add_option("--bytes-per-inode", dest="bytesPerInode", action="store",
+ type="int", nargs=1)
+ return op
+
+class RHEL5_Raid(FC5_Raid):
+ removedKeywords = FC5_Raid.removedKeywords
+ removedAttrs = FC5_Raid.removedAttrs
+
+ def __init__(self, writePriority=131, *args, **kwargs):
+ FC5_Raid.__init__(self, writePriority, *args, **kwargs)
+
+ self.levelMap.update({"RAID10": "RAID10", "10": "RAID10"})
+
+ def _getParser(self):
+ op = FC5_Raid._getParser(self)
+ op.add_option("--encrypted", action="store_true", default=False)
+ op.add_option("--passphrase")
+ return op
+
+class F7_Raid(FC5_Raid):
+ removedKeywords = FC5_Raid.removedKeywords
+ removedAttrs = FC5_Raid.removedAttrs
+
+ def __init__(self, writePriority=131, *args, **kwargs):
+ FC5_Raid.__init__(self, writePriority, *args, **kwargs)
+
+ self.levelMap.update({"RAID10": "RAID10", "10": "RAID10"})
+
+class F9_Raid(F7_Raid):
+ removedKeywords = F7_Raid.removedKeywords
+ removedAttrs = F7_Raid.removedAttrs
+
+ def _getParser(self):
+ op = F7_Raid._getParser(self)
+ op.add_option("--bytes-per-inode", deprecated=1)
+ op.add_option("--fsprofile")
+ op.add_option("--encrypted", action="store_true", default=False)
+ op.add_option("--passphrase")
+ return op
+
+class F12_Raid(F9_Raid):
+ removedKeywords = F9_Raid.removedKeywords
+ removedAttrs = F9_Raid.removedAttrs
+
+ def _getParser(self):
+ op = F9_Raid._getParser(self)
+ op.add_option("--escrowcert")
+ op.add_option("--backuppassphrase", action="store_true", default=False)
+ return op
+
+class F13_Raid(F12_Raid):
+ removedKeywords = F12_Raid.removedKeywords
+ removedAttrs = F12_Raid.removedAttrs
+
+ def __init__(self, writePriority=131, *args, **kwargs):
+ F12_Raid.__init__(self, writePriority, *args, **kwargs)
+
+ self.levelMap.update({"RAID4": "RAID4", "4": "RAID4"})
+
+class F14_Raid(F13_Raid):
+ removedKeywords = F13_Raid.removedKeywords
+ removedAttrs = F13_Raid.removedAttrs
+
+ def _getParser(self):
+ op = F13_Raid._getParser(self)
+ op.remove_option("--bytes-per-inode")
+ return op
+
+class F15_Raid(F14_Raid):
+ removedKeywords = F14_Raid.removedKeywords
+ removedAttrs = F14_Raid.removedAttrs
+
+ def _getParser(self):
+ op = F14_Raid._getParser(self)
+ op.add_option("--label")
+ return op
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.constants import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+class FC3_Reboot(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.action = kwargs.get("action", None)
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.action == KS_REBOOT:
+ retval += "# Reboot after installation\nreboot\n"
+ elif self.action == KS_SHUTDOWN:
+ retval += "# Shutdown after installation\nshutdown\n"
+
+ return retval
+
+ def parse(self, args):
+ if self.currentCmd == "reboot":
+ self.action = KS_REBOOT
+ else:
+ self.action = KS_SHUTDOWN
+
+ return self
+
+class FC6_Reboot(FC3_Reboot):
+ removedKeywords = FC3_Reboot.removedKeywords
+ removedAttrs = FC3_Reboot.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ FC3_Reboot.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.eject = kwargs.get("eject", False)
+
+ def __str__(self):
+ retval = FC3_Reboot.__str__(self).rstrip()
+
+ if self.eject:
+ retval += " --eject"
+
+ return retval + "\n"
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--eject", dest="eject", action="store_true",
+ default=False)
+ return op
+
+ def parse(self, args):
+ FC3_Reboot.parse(self, args)
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ self._setToSelf(self.op, opts)
+ return self
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2007, 2008, 2009 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.constants import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+import warnings
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC6_RepoData(BaseData):
+ removedKeywords = BaseData.removedKeywords
+ removedAttrs = BaseData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ BaseData.__init__(self, *args, **kwargs)
+ self.baseurl = kwargs.get("baseurl", "")
+ self.mirrorlist = kwargs.get("mirrorlist", None)
+ self.name = kwargs.get("name", "")
+
+ def __eq__(self, y):
+ return self.name == y.name
+
+ def _getArgsAsStr(self):
+ retval = ""
+
+ if self.baseurl:
+ retval += "--baseurl=%s" % self.baseurl
+ elif self.mirrorlist:
+ retval += "--mirrorlist=%s" % self.mirrorlist
+
+ return retval
+
+ def __str__(self):
+ retval = BaseData.__str__(self)
+ retval += "repo --name=\"%s\" %s\n" % (self.name, self._getArgsAsStr())
+ return retval
+
+class F8_RepoData(FC6_RepoData):
+ removedKeywords = FC6_RepoData.removedKeywords
+ removedAttrs = FC6_RepoData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ FC6_RepoData.__init__(self, *args, **kwargs)
+ self.cost = kwargs.get("cost", None)
+ self.includepkgs = kwargs.get("includepkgs", [])
+ self.excludepkgs = kwargs.get("excludepkgs", [])
+
+ def _getArgsAsStr(self):
+ retval = FC6_RepoData._getArgsAsStr(self)
+
+ if self.cost:
+ retval += " --cost=%s" % self.cost
+ if self.includepkgs:
+ retval += " --includepkgs=\"%s\"" % ",".join(self.includepkgs)
+ if self.excludepkgs:
+ retval += " --excludepkgs=\"%s\"" % ",".join(self.excludepkgs)
+
+ return retval
+
+class F11_RepoData(F8_RepoData):
+ removedKeywords = F8_RepoData.removedKeywords
+ removedAttrs = F8_RepoData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ F8_RepoData.__init__(self, *args, **kwargs)
+ self.ignoregroups = kwargs.get("ignoregroups", None)
+
+ def _getArgsAsStr(self):
+ retval = F8_RepoData._getArgsAsStr(self)
+
+ if self.ignoregroups:
+ retval += " --ignoregroups=true"
+ return retval
+
+class F13_RepoData(F11_RepoData):
+ removedKeywords = F11_RepoData.removedKeywords
+ removedAttrs = F11_RepoData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ F11_RepoData.__init__(self, *args, **kwargs)
+ self.proxy = kwargs.get("proxy", "")
+
+ def _getArgsAsStr(self):
+ retval = F11_RepoData._getArgsAsStr(self)
+
+ if self.proxy:
+ retval += " --proxy=\"%s\"" % self.proxy
+
+ return retval
+
+class F14_RepoData(F13_RepoData):
+ removedKeywords = F13_RepoData.removedKeywords
+ removedAttrs = F13_RepoData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ F13_RepoData.__init__(self, *args, **kwargs)
+ self.noverifyssl = kwargs.get("noverifyssl", False)
+
+ def _getArgsAsStr(self):
+ retval = F13_RepoData._getArgsAsStr(self)
+
+ if self.noverifyssl:
+ retval += " --noverifyssl"
+
+ return retval
+
+RHEL6_RepoData = F14_RepoData
+
+F15_RepoData = F14_RepoData
+
+class FC6_Repo(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ urlRequired = True
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.repoList = kwargs.get("repoList", [])
+
+ def __str__(self):
+ retval = ""
+ for repo in self.repoList:
+ retval += repo.__str__()
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--name", dest="name", required=1)
+ op.add_option("--baseurl")
+ op.add_option("--mirrorlist")
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+
+ if len(extra) != 0:
+ mapping = {"command": "repo", "options": extra}
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Unexpected arguments to %(command)s command: %(options)s") % mapping))
+
+ # This is lame, but I can't think of a better way to make sure only
+ # one of these two is specified.
+ if opts.baseurl and opts.mirrorlist:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Only one of --baseurl and --mirrorlist may be specified for repo command.")))
+
+ if self.urlRequired and not opts.baseurl and not opts.mirrorlist:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("One of --baseurl or --mirrorlist must be specified for repo command.")))
+
+ rd = self.handler.RepoData()
+ self._setToObj(self.op, opts, rd)
+ rd.lineno = self.lineno
+
+ # Check for duplicates in the data list.
+ if rd in self.dataList():
+ warnings.warn(_("A repo with the name %s has already been defined.") % rd.name)
+
+ return rd
+
+ def dataList(self):
+ return self.repoList
+
+class F8_Repo(FC6_Repo):
+ removedKeywords = FC6_Repo.removedKeywords
+ removedAttrs = FC6_Repo.removedAttrs
+
+ def __str__(self):
+ retval = ""
+ for repo in self.repoList:
+ retval += repo.__str__()
+
+ return retval
+
+ def _getParser(self):
+ def list_cb (option, opt_str, value, parser):
+ for d in value.split(','):
+ parser.values.ensure_value(option.dest, []).append(d)
+
+ op = FC6_Repo._getParser(self)
+ op.add_option("--cost", action="store", type="int")
+ op.add_option("--excludepkgs", action="callback", callback=list_cb,
+ nargs=1, type="string")
+ op.add_option("--includepkgs", action="callback", callback=list_cb,
+ nargs=1, type="string")
+ return op
+
+ def methodToRepo(self):
+ if not self.handler.method.url:
+ raise KickstartError (formatErrorMsg(self.handler.method.lineno, msg=_("Method must be a url to be added to the repo list.")))
+ reponame = "ks-method-url"
+ repourl = self.handler.method.url
+ rd = self.handler.RepoData(name=reponame, baseurl=repourl)
+ return rd
+
+class F11_Repo(F8_Repo):
+ removedKeywords = F8_Repo.removedKeywords
+ removedAttrs = F8_Repo.removedAttrs
+
+ def _getParser(self):
+ op = F8_Repo._getParser(self)
+ op.add_option("--ignoregroups", action="store", type="ksboolean")
+ return op
+
+class F13_Repo(F11_Repo):
+ removedKeywords = F11_Repo.removedKeywords
+ removedAttrs = F11_Repo.removedAttrs
+
+ def _getParser(self):
+ op = F11_Repo._getParser(self)
+ op.add_option("--proxy")
+ return op
+
+class F14_Repo(F13_Repo):
+ removedKeywords = F13_Repo.removedKeywords
+ removedAttrs = F13_Repo.removedAttrs
+
+ def _getParser(self):
+ op = F13_Repo._getParser(self)
+ op.add_option("--noverifyssl", action="store_true", default=False)
+ return op
+
+RHEL6_Repo = F14_Repo
+
+class F15_Repo(F14_Repo):
+ removedKeywords = F14_Repo.removedKeywords
+ removedAttrs = F14_Repo.removedAttrs
+
+ urlRequired = False
--- /dev/null
+#
+# Alexander Todorov <atodorov@redhat.com>
+#
+# Copyright 2008 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class F10_Rescue(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.rescue = False
+ self.nomount = kwargs.get("nomount", False)
+ self.romount = kwargs.get("romount", False)
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.rescue:
+ retval += "rescue"
+
+ if self.nomount:
+ retval += " --nomount"
+ if self.romount:
+ retval += " --romount"
+
+ retval = "# Start rescue mode\n%s\n" % retval
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--nomount", dest="nomount", action="store_true", default=False)
+ op.add_option("--romount", dest="romount", action="store_true", default=False)
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+
+ if opts.nomount and opts.romount:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Only one of --nomount and --romount may be specified for rescue command.")))
+
+ self._setToSelf(self.op, opts)
+ self.rescue = True
+ return self
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_RootPw(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.isCrypted = kwargs.get("isCrypted", False)
+ self.password = kwargs.get("password", "")
+
+ def _getArgsAsStr(self):
+ retval = ""
+
+ if self.isCrypted:
+ retval += " --iscrypted"
+
+ return retval
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.password != "":
+ retval += "# Root password\nrootpw%s %s\n" % (self._getArgsAsStr(), self.password)
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--iscrypted", dest="isCrypted", action="store_true",
+ default=False)
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ self._setToSelf(self.op, opts)
+
+ if len(extra) != 1:
+ raise KickstartValueError ( formatErrorMsg(self.lineno, msg=_("A single argument is expected for the %s command") % "rootpw"))
+
+ self.password = extra[0]
+ return self
+
+class F8_RootPw(FC3_RootPw):
+ removedKeywords = FC3_RootPw.removedKeywords
+ removedAttrs = FC3_RootPw.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ FC3_RootPw.__init__(self, writePriority, *args, **kwargs)
+ self.lock = kwargs.get("lock", False)
+
+ def _getArgsAsStr(self):
+ retval = FC3_RootPw._getArgsAsStr(self)
+
+ if self.lock:
+ retval += " --lock"
+
+ if not self.isCrypted:
+ retval += " --plaintext"
+
+ return retval
+
+ def _getParser(self):
+ op = FC3_RootPw._getParser(self)
+ op.add_option("--lock", dest="lock", action="store_true", default=False)
+ op.add_option("--plaintext", dest="isCrypted", action="store_false")
+ return op
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.constants import *
+from pykickstart.options import *
+
+class FC3_SELinux(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.selinux = kwargs.get("selinux", None)
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if not retval and self.selinux is None:
+ return ""
+
+ retval += "# SELinux configuration\n"
+
+ if self.selinux == SELINUX_DISABLED:
+ retval += "selinux --disabled\n"
+ elif self.selinux == SELINUX_ENFORCING:
+ retval += "selinux --enforcing\n"
+ elif self.selinux == SELINUX_PERMISSIVE:
+ retval += "selinux --permissive\n"
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--disabled", dest="selinux", action="store_const",
+ const=SELINUX_DISABLED)
+ op.add_option("--enforcing", dest="selinux", action="store_const",
+ const=SELINUX_ENFORCING)
+ op.add_option("--permissive", dest="selinux", action="store_const",
+ const=SELINUX_PERMISSIVE)
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ self._setToSelf(self.op, opts)
+ return self
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC6_Services(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.disabled = kwargs.get("disabled", [])
+ self.enabled = kwargs.get("enabled", [])
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+ args = ""
+
+ if len(self.disabled) > 0:
+ args += " --disabled=\"%s\"" % ",".join(self.disabled)
+ if len(self.enabled) > 0:
+ args += " --enabled=\"%s\"" % ",".join(self.enabled)
+
+ if args != "":
+ retval += "# System services\nservices%s\n" % args
+
+ return retval
+
+ def _getParser(self):
+ def services_cb (option, opt_str, value, parser):
+ for d in value.split(','):
+ parser.values.ensure_value(option.dest, []).append(d.strip())
+
+ op = KSOptionParser()
+ op.add_option("--disabled", dest="disabled", action="callback",
+ callback=services_cb, nargs=1, type="string")
+ op.add_option("--enabled", dest="enabled", action="callback",
+ callback=services_cb, nargs=1, type="string")
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ self._setToSelf(self.op, opts)
+
+ if len(self.disabled) == 0 and len(self.enabled) == 0:
+ raise KickstartParseError (formatErrorMsg(self.lineno, msg=_("One of --disabled or --enabled must be provided.")))
+
+ return self
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_SkipX(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+ self.skipx = kwargs.get("skipx", False)
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.skipx:
+ retval += "# Do not configure the X Window System\nskipx\n"
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ if len(extra) > 0:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Kickstart command %s does not take any arguments") % "skipx"))
+
+ self.skipx = True
+ return self
--- /dev/null
+#
+# Peter Jones <pjones@redhat.com>
+#
+# Copyright 2009 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class F13_SshPwData(BaseData):
+ removedKeywords = BaseData.removedKeywords
+ removedAttrs = BaseData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ BaseData.__init__(self, *args, **kwargs)
+ self.username = kwargs.get("username", None)
+ self.isCrypted = kwargs.get("isCrypted", False)
+ self.password = kwargs.get("password", "")
+ self.lock = kwargs.get("lock", False)
+
+ def __eq__(self, y):
+ return self.username == y.username
+
+ def __str__(self):
+ retval = BaseData.__str__(self)
+
+ retval += "sshpw"
+ retval += self._getArgsAsStr() + '\n'
+
+ return retval
+
+ def _getArgsAsStr(self):
+ retval = ""
+
+ retval += " --username=%s" % self.username
+ if self.lock:
+ retval += " --lock"
+ if self.isCrypted:
+ retval += " --iscrypted"
+ else:
+ retval += " --plaintext"
+
+ retval += " %s" % self.password
+ return retval
+
+class F13_SshPw(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.sshUserList = kwargs.get("sshUserList", [])
+
+ def __str__(self):
+ retval = ""
+ for user in self.sshUserList:
+ retval += user.__str__()
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--username", dest="username", required=True)
+ op.add_option("--iscrypted", dest="isCrypted", action="store_true",
+ default=False)
+ op.add_option("--plaintext", dest="isCrypted", action="store_false")
+ op.add_option("--lock", dest="lock", action="store_true", default=False)
+ return op
+
+ def parse(self, args):
+ ud = self.handler.SshPwData()
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ self._setToObj(self.op, opts, ud)
+ ud.lineno = self.lineno
+
+ if len(extra) != 1:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("A single argument is expected for the %s command") % "sshpw"))
+ ud.password = extra[0]
+
+ if ud in self.dataList():
+ warnings.warn(_("An ssh user with the name %s has already been defined.") % ud.name)
+
+ return ud
+
+ def dataList(self):
+ return self.sshUserList
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_Timezone(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.isUtc = kwargs.get("isUtc", False)
+ self.timezone = kwargs.get("timezone", "")
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.timezone != "":
+ if self.isUtc:
+ utc = "--utc"
+ else:
+ utc = ""
+
+ retval += "# System timezone\ntimezone %s %s\n" %(utc, self.timezone)
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--utc", dest="isUtc", action="store_true", default=False)
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ self._setToSelf(self.op, opts)
+
+ if len(extra) != 1:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("A single argument is expected for the %s command") % "timezone"))
+
+ self.timezone = extra[0]
+ return self
+
+class FC6_Timezone(FC3_Timezone):
+ removedKeywords = FC3_Timezone.removedKeywords
+ removedAttrs = FC3_Timezone.removedAttrs
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.timezone != "":
+ if self.isUtc:
+ utc = "--isUtc"
+ else:
+ utc = ""
+
+ retval += "# System timezone\ntimezone %s %s\n" %(utc, self.timezone)
+
+ return retval
+
+ def _getParser(self):
+ op = FC3_Timezone._getParser(self)
+ op.add_option("--utc", "--isUtc", dest="isUtc", action="store_true", default=False)
+ return op
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class F7_Updates(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+ self.url = kwargs.get("url", "")
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.url == "floppy":
+ retval += "updates\n"
+ elif self.url != "":
+ retval += "updates %s\n" % self.url
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+
+ if len(extra) > 1:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Kickstart command %s only takes one argument") % "updates"))
+ elif len(extra) == 0:
+ self.url = "floppy"
+ else:
+ self.url = extra[0]
+
+ return self
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_Upgrade(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.upgrade = kwargs.get("upgrade", None)
+ self.op = self._getParser()
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.upgrade is None:
+ return retval
+
+ if self.upgrade:
+ retval += "# Upgrade existing installation\nupgrade\n"
+ else:
+ retval += "# Install OS instead of upgrade\ninstall\n"
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+
+ if len(extra) > 0:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Kickstart command %s does not take any arguments") % "upgrade"))
+
+ if self.currentCmd == "upgrade":
+ self.upgrade = True
+ else:
+ self.upgrade = False
+
+ return self
+
+class F11_Upgrade(FC3_Upgrade):
+ removedKeywords = FC3_Upgrade.removedKeywords
+ removedAttrs = FC3_Upgrade.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ FC3_Upgrade.__init__(self, writePriority, *args, **kwargs)
+
+ self.op = self._getParser()
+ self.root_device = kwargs.get("root_device", None)
+
+ def __str__(self):
+ if self.upgrade and (self.root_device is not None):
+ retval = KickstartCommand.__str__(self)
+ retval += "# Upgrade existing installation\nupgrade --root-device=%s\n" % self.root_device
+ else:
+ retval = FC3_Upgrade.__str__(self)
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--root-device", dest="root_device")
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+
+ if len(extra) > 0:
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Kickstart command %s does not take any arguments") % "upgrade"))
+
+ if (opts.root_device is not None) and (opts.root_device == ""):
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Kickstart command %s does not accept empty parameter %s") % ("upgrade", "--root-device")))
+ else:
+ self.root_device = opts.root_device
+
+ if self.currentCmd == "upgrade":
+ self.upgrade = True
+ else:
+ self.upgrade = False
+
+ return self
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.constants import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+import warnings
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC6_UserData(BaseData):
+ removedKeywords = BaseData.removedKeywords
+ removedAttrs = BaseData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ BaseData.__init__(self, *args, **kwargs)
+ self.groups = kwargs.get("groups", [])
+ self.homedir = kwargs.get("homedir", "")
+ self.isCrypted = kwargs.get("isCrypted", False)
+ self.name = kwargs.get("name", "")
+ self.password = kwargs.get("password", "")
+ self.shell = kwargs.get("shell", "")
+ self.uid = kwargs.get("uid", None)
+
+ def __eq__(self, y):
+ return self.name == y.name
+
+ def __str__(self):
+ retval = BaseData.__str__(self)
+
+ if self.uid != "":
+ retval += "user"
+ retval += self._getArgsAsStr() + "\n"
+
+ return retval
+
+ def _getArgsAsStr(self):
+ retval = ""
+
+ if len(self.groups) > 0:
+ retval += " --groups=%s" % ",".join(self.groups)
+ if self.homedir:
+ retval += " --homedir=%s" % self.homedir
+ if self.name:
+ retval += " --name=%s" % self.name
+ if self.password:
+ retval += " --password=%s" % self.password
+ if self.isCrypted:
+ retval += " --iscrypted"
+ if self.shell:
+ retval += " --shell=%s" % self.shell
+ if self.uid:
+ retval += " --uid=%s" % self.uid
+
+ return retval
+
+class F8_UserData(FC6_UserData):
+ removedKeywords = FC6_UserData.removedKeywords
+ removedAttrs = FC6_UserData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ FC6_UserData.__init__(self, *args, **kwargs)
+ self.lock = kwargs.get("lock", False)
+
+ def _getArgsAsStr(self):
+ retval = FC6_UserData._getArgsAsStr(self)
+
+ if self.lock:
+ retval += " --lock"
+
+ return retval
+
+class F12_UserData(F8_UserData):
+ removedKeywords = F8_UserData.removedKeywords
+ removedAttrs = F8_UserData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ F8_UserData.__init__(self, *args, **kwargs)
+ self.gecos = kwargs.get("gecos", "")
+
+ def _getArgsAsStr(self):
+ retval = F8_UserData._getArgsAsStr(self)
+
+ if self.gecos:
+ retval += " --gecos=\"%s\"" % (self.gecos,)
+
+ return retval
+
+class FC6_User(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.userList = kwargs.get("userList", [])
+
+ def __str__(self):
+ retval = ""
+ for user in self.userList:
+ retval += user.__str__()
+
+ return retval
+
+ def _getParser(self):
+ def groups_cb (option, opt_str, value, parser):
+ for d in value.split(','):
+ parser.values.ensure_value(option.dest, []).append(d)
+
+ op = KSOptionParser()
+ op.add_option("--groups", dest="groups", action="callback",
+ callback=groups_cb, nargs=1, type="string")
+ op.add_option("--homedir")
+ op.add_option("--iscrypted", dest="isCrypted", action="store_true",
+ default=False)
+ op.add_option("--name", required=1)
+ op.add_option("--password")
+ op.add_option("--shell")
+ op.add_option("--uid", type="int")
+ return op
+
+ def parse(self, args):
+ ud = self.handler.UserData()
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ self._setToObj(self.op, opts, ud)
+ ud.lineno = self.lineno
+
+ # Check for duplicates in the data list.
+ if ud in self.dataList():
+ warnings.warn(_("A user with the name %s has already been defined.") % ud.name)
+
+ return ud
+
+ def dataList(self):
+ return self.userList
+
+class F8_User(FC6_User):
+ removedKeywords = FC6_User.removedKeywords
+ removedAttrs = FC6_User.removedAttrs
+
+ def _getParser(self):
+ op = FC6_User._getParser(self)
+ op.add_option("--lock", action="store_true", default=False)
+ op.add_option("--plaintext", dest="isCrypted", action="store_false")
+ return op
+
+class F12_User(F8_User):
+ removedKeywords = F8_User.removedKeywords
+ removedAttrs = F8_User.removedAttrs
+
+ def _getParser(self):
+ op = F8_User._getParser(self)
+ op.add_option("--gecos", type="string")
+ return op
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+class FC3_Vnc(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.enabled = kwargs.get("enabled", False)
+ self.password = kwargs.get("password", "")
+ self.connect = kwargs.get("connect", "")
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if not self.enabled:
+ return retval
+
+ retval += "vnc"
+
+ if self.connect != "":
+ retval += " --connect=%s" % self.connect
+ if self.password != "":
+ retval += " --password=%s" % self.password
+
+ return retval + "\n"
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--connect")
+ op.add_option("--password", dest="password")
+ return op
+
+ def parse(self, args):
+ self.enabled = True
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ self._setToSelf(self.op, opts)
+ return self
+
+class FC6_Vnc(FC3_Vnc):
+ removedKeywords = FC3_Vnc.removedKeywords + ["connect"]
+ removedAttrs = FC3_Vnc.removedAttrs + ["connect"]
+
+ def __init__(self, writePriority=0, host="", port="", *args, **kwargs):
+ FC3_Vnc.__init__(self, writePriority, *args, **kwargs)
+ self.deleteRemovedAttrs()
+
+ self.host = kwargs.get("host", "")
+ self.port = kwargs.get("port", "")
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if not self.enabled:
+ return retval
+
+ retval += "vnc"
+
+ if self.host != "":
+ retval += " --host=%s" % self.host
+
+ if self.port != "":
+ retval += " --port=%s" % self.port
+ if self.password != "":
+ retval += " --password=%s" % self.password
+
+ return retval + "\n"
+
+ def _getParser(self):
+ def connect_cb (option, opt_str, value, parser):
+ cargs = value.split(":")
+ parser.values.ensure_value("host", cargs[0])
+
+ if len(cargs) > 1:
+ parser.values.ensure_value("port", cargs[1])
+
+ op = FC3_Vnc._getParser(self)
+ op.add_option("--connect", action="callback", callback=connect_cb,
+ nargs=1, type="string")
+ op.add_option("--host", dest="host")
+ op.add_option("--port", dest="port")
+ return op
+
+class F9_Vnc(FC6_Vnc):
+ removedKeywords = FC6_Vnc.removedKeywords
+ removedAttrs = FC6_Vnc.removedAttrs
+
+ def _getParser(self):
+ op = FC6_Vnc._getParser(self)
+ op.remove_option("--connect")
+ return op
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.options import *
+
+import gettext
+import warnings
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_VolGroupData(BaseData):
+ removedKeywords = BaseData.removedKeywords
+ removedAttrs = BaseData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ BaseData.__init__(self, *args, **kwargs)
+ self.format = kwargs.get("format", True)
+ self.pesize = kwargs.get("pesize", 32768)
+ self.preexist = kwargs.get("preexist", False)
+ self.vgname = kwargs.get("vgname", "")
+ self.physvols = kwargs.get("physvols", [])
+
+ def __eq__(self, y):
+ return self.vgname == y.vgname
+
+ def __str__(self):
+ retval = BaseData.__str__(self)
+ retval += "volgroup %s" % self.vgname
+
+ if not self.format:
+ retval += " --noformat"
+ if self.pesize != 0:
+ retval += " --pesize=%d" % self.pesize
+ if self.preexist:
+ retval += " --useexisting"
+
+ return retval + " " + " ".join(self.physvols) + "\n"
+
+class FC3_VolGroup(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=132, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.vgList = kwargs.get("vgList", [])
+
+ def __str__(self):
+ retval = ""
+ for vg in self.vgList:
+ retval += vg.__str__()
+
+ return retval
+
+ def _getParser(self):
+ # Have to be a little more complicated to set two values.
+ def vg_cb (option, opt_str, value, parser):
+ parser.values.format = False
+ parser.values.preexist = True
+
+ op = KSOptionParser()
+ op.add_option("--noformat", action="callback", callback=vg_cb,
+ dest="format", default=True, nargs=0)
+ op.add_option("--pesize", dest="pesize", type="int", nargs=1,
+ default=32768)
+ op.add_option("--useexisting", dest="preexist", action="store_true",
+ default=False)
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ vg = self.handler.VolGroupData()
+ self._setToObj(self.op, opts, vg)
+ vg.lineno = self.lineno
+ vg.vgname = extra[0]
+ vg.physvols = extra[1:]
+
+ # Check for duplicates in the data list.
+ if vg in self.dataList():
+ warnings.warn(_("A volgroup with the name %s has already been defined.") % vg.vgname)
+
+ return vg
+
+ def dataList(self):
+ return self.vgList
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007, 2008 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_XConfig(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.card = kwargs.get("card", "")
+ self.defaultdesktop = kwargs.get("defaultdesktop", "")
+ self.depth = kwargs.get("depth", 0)
+ self.hsync = kwargs.get("hsync", "")
+ self.monitor = kwargs.get("monitor", "")
+ self.noProbe = kwargs.get("noProbe", False)
+ self.resolution = kwargs.get("resolution", "")
+ self.server = kwargs.get("server", "")
+ self.startX = kwargs.get("startX", False)
+ self.videoRam = kwargs.get("videoRam", "")
+ self.vsync = kwargs.get("vsync", "")
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.card != "":
+ retval += " --card=%s" % self.card
+ if self.defaultdesktop != "":
+ retval += " --defaultdesktop=%s" % self.defaultdesktop
+ if self.depth != 0:
+ retval += " --depth=%d" % self.depth
+ if self.hsync != "":
+ retval += " --hsync=%s" % self.hsync
+ if self.monitor != "":
+ retval += " --monitor=%s" % self.monitor
+ if self.noProbe:
+ retval += " --noprobe"
+ if self.resolution != "":
+ retval += " --resolution=%s" % self.resolution
+ if self.server != "":
+ retval += " --server=%s" % self.server
+ if self.startX:
+ retval += " --startxonboot"
+ if self.videoRam != "":
+ retval += " --videoram=%s" % self.videoRam
+ if self.vsync != "":
+ retval += " --vsync=%s" % self.vsync
+
+ if retval != "":
+ retval = "# X Window System configuration information\nxconfig %s\n" % retval
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--card")
+ op.add_option("--defaultdesktop")
+ op.add_option("--depth", action="store", type="int", nargs=1)
+ op.add_option("--hsync")
+ op.add_option("--monitor")
+ op.add_option("--noprobe", dest="noProbe", action="store_true",
+ default=False)
+ op.add_option("--resolution")
+ op.add_option("--server")
+ op.add_option("--startxonboot", dest="startX", action="store_true",
+ default=False)
+ op.add_option("--videoram", dest="videoRam")
+ op.add_option("--vsync")
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ if extra:
+ mapping = {"command": "xconfig", "options": extra}
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=_("Unexpected arguments to %(command)s command: %(options)s") % mapping))
+
+ self._setToSelf(self.op, opts)
+ return self
+
+class FC6_XConfig(FC3_XConfig):
+ removedKeywords = FC3_XConfig.removedKeywords + ["card", "hsync", "monitor", "noProbe", "vsync"]
+ removedAttrs = FC3_XConfig.removedAttrs + ["card", "hsync", "monitor", "noProbe", "vsync"]
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ FC3_XConfig.__init__(self, writePriority, *args, **kwargs)
+ self.deleteRemovedAttrs()
+
+ self.driver = kwargs.get("driver", "")
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if hasattr(self, "driver") and self.driver != "":
+ retval += " --driver=%s" % self.driver
+ if self.defaultdesktop != "":
+ retval += " --defaultdesktop=%s" % self.defaultdesktop
+ if self.depth != 0:
+ retval += " --depth=%d" % self.depth
+ if hasattr(self, "resolution") and self.resolution != "":
+ retval += " --resolution=%s" % self.resolution
+ if self.startX:
+ retval += " --startxonboot"
+ if hasattr(self, "videoRam") and self.videoRam != "":
+ retval += " --videoram=%s" % self.videoRam
+
+ if retval != "":
+ retval = "# X Window System configuration information\nxconfig %s\n" % retval
+
+ return retval
+
+ def _getParser(self):
+ op = FC3_XConfig._getParser(self)
+ op.add_option("--card", deprecated=1)
+ op.add_option("--driver", dest="driver")
+ op.add_option("--hsync", deprecated=1)
+ op.add_option("--monitor", deprecated=1)
+ op.add_option("--noprobe", deprecated=1)
+ op.add_option("--vsync", deprecated=1)
+ return op
+
+class F9_XConfig(FC6_XConfig):
+ removedKeywords = FC6_XConfig.removedKeywords
+ removedAttrs = FC6_XConfig.removedAttrs
+
+ def _getParser(self):
+ op = FC6_XConfig._getParser(self)
+ op.remove_option("--card")
+ op.remove_option("--hsync")
+ op.remove_option("--monitor")
+ op.remove_option("--noprobe")
+ op.remove_option("--vsync")
+ return op
+
+class F10_XConfig(F9_XConfig):
+ removedKeywords = F9_XConfig.removedKeywords + ["driver", "resolution", "videoRam"]
+ removedAttrs = F9_XConfig.removedAttrs + ["driver", "resolution", "videoRam"]
+
+ def __init__(self, writePriority=0, *args, **kwargs):
+ F9_XConfig.__init__(self, writePriority, *args, **kwargs)
+ self.deleteRemovedAttrs()
+
+ def _getParser(self):
+ op = F9_XConfig._getParser(self)
+ op.add_option("--driver", deprecated=1)
+ op.add_option("--depth", deprecated=1)
+ op.add_option("--resolution", deprecated=1)
+ op.add_option("--videoram", deprecated=1)
+ return op
+
+class F14_XConfig(F10_XConfig):
+ removedKeywords = F10_XConfig.removedKeywords
+ removedAttrs = F10_XConfig.removedAttrs
+
+ def _getParser(self):
+ op = F10_XConfig._getParser(self)
+ op.remove_option("--driver")
+ op.remove_option("--depth")
+ op.remove_option("--resolution")
+ op.remove_option("--videoram")
+ return op
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+import warnings
+
+from pykickstart.base import *
+from pykickstart.options import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_ZeroMbr(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=110, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+ self.zerombr = kwargs.get("zerombr", False)
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.zerombr:
+ retval += "# Clear the Master Boot Record\nzerombr\n"
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ return op
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+
+ if len(extra) > 0:
+ warnings.warn(_("Ignoring deprecated option on line %s: The zerombr command no longer takes any options. In future releases, this will result in a fatal error from kickstart. Please modify your kickstart file to remove any options.") % self.lineno, DeprecationWarning)
+
+ self.zerombr = True
+ return self
+
+class F9_ZeroMbr(FC3_ZeroMbr):
+ removedKeywords = FC3_ZeroMbr.removedKeywords
+ removedAttrs = FC3_ZeroMbr.removedAttrs
+
+ def parse(self, args):
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+
+ if len(extra) > 0:
+ raise KickstartParseError (formatErrorMsg(self.lineno, msg=_("Kickstart command %s does not take any arguments") % "zerombr"))
+
+ self.zerombr = True
+ return self
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.options import *
+
+import gettext
+import warnings
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class FC3_ZFCPData(BaseData):
+ removedKeywords = BaseData.removedKeywords
+ removedAttrs = BaseData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ BaseData.__init__(self, *args, **kwargs)
+ self.devnum = kwargs.get("devnum", "")
+ self.wwpn = kwargs.get("wwpn", "")
+ self.fcplun = kwargs.get("fcplun", "")
+ self.scsiid = kwargs.get("scsiid", "")
+ self.scsilun = kwargs.get("scsilun", "")
+
+ def __eq__(self, y):
+ return self.devnum == y.devnum and self.wwpn == y.wwpn and \
+ self.fcplun == y.fcplun and self.scsiid == y.scsiid and \
+ self.scsilun == y.scsilun
+
+ def __str__(self):
+ retval = BaseData.__str__(self)
+ retval += "zfcp"
+
+ if self.devnum != "":
+ retval += " --devnum=%s" % self.devnum
+ if self.wwpn != "":
+ retval += " --wwpn=%s" % self.wwpn
+ if self.fcplun != "":
+ retval += " --fcplun=%s" % self.fcplun
+ if hasattr(self, "scsiid") and self.scsiid != "":
+ retval += " --scsiid=%s" % self.scsiid
+ if hasattr(self, "scsilun") and self.scsilun != "":
+ retval += " --scsilun=%s" % self.scsilun
+
+ return retval + "\n"
+
+class F12_ZFCPData(FC3_ZFCPData):
+ removedKeywords = FC3_ZFCPData.removedKeywords + ["scsiid", "scsilun"]
+ removedAttrs = FC3_ZFCPData.removedAttrs + ["scsiid", "scsilun"]
+
+ def __init__(self, *args, **kwargs):
+ FC3_ZFCPData.__init__(self, *args, **kwargs)
+ self.deleteRemovedAttrs()
+
+F14_ZFCPData = F12_ZFCPData
+
+class FC3_ZFCP(KickstartCommand):
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, writePriority=71, *args, **kwargs):
+ KickstartCommand.__init__(self, writePriority, *args, **kwargs)
+ self.op = self._getParser()
+
+ self.zfcp = kwargs.get("zfcp", [])
+
+ def __str__(self):
+ retval = ""
+ for zfcp in self.zfcp:
+ retval += zfcp.__str__()
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ op.add_option("--devnum", dest="devnum", required=1)
+ op.add_option("--fcplun", dest="fcplun", required=1)
+ op.add_option("--scsiid", dest="scsiid", required=1)
+ op.add_option("--scsilun", dest="scsilun", required=1)
+ op.add_option("--wwpn", dest="wwpn", required=1)
+ return op
+
+ def parse(self, args):
+ zd = self.handler.ZFCPData()
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ self._setToObj(self.op, opts, zd)
+ zd.lineno = self.lineno
+
+ # Check for duplicates in the data list.
+ if zd in self.dataList():
+ warnings.warn(_("A zfcp with this information has already been defined."))
+
+ return zd
+
+ def dataList(self):
+ return self.zfcp
+
+class F12_ZFCP(FC3_ZFCP):
+ removedKeywords = FC3_ZFCP.removedKeywords
+ removedAttrs = FC3_ZFCP.removedAttrs + ["scsiid", "scsilun"]
+
+ def __init__(self, *args, **kwargs):
+ FC3_ZFCP.__init__(self, *args, **kwargs)
+ self.deleteRemovedAttrs()
+
+ def _getParser(self):
+ op = FC3_ZFCP._getParser(self)
+ op.add_option("--scsiid", deprecated=1)
+ op.add_option("--scsilun", deprecated=1)
+ return op
+
+class F14_ZFCP(F12_ZFCP):
+ removedKeywords = F12_ZFCP.removedKeywords
+ removedAttrs = F12_ZFCP.removedAttrs
+
+ def _getParser(self):
+ op = F12_ZFCP._getParser(self)
+ op.remove_option("--scsiid")
+ op.remove_option("--scsilun")
+ return op
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005-2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+CLEARPART_TYPE_LINUX = 0
+CLEARPART_TYPE_ALL = 1
+CLEARPART_TYPE_NONE = 2
+
+DISPLAY_MODE_CMDLINE = 0
+DISPLAY_MODE_GRAPHICAL = 1
+DISPLAY_MODE_TEXT = 2
+
+FIRSTBOOT_DEFAULT = 0
+FIRSTBOOT_SKIP = 1
+FIRSTBOOT_RECONFIG = 2
+
+KS_MISSING_PROMPT = 0
+KS_MISSING_IGNORE = 1
+
+SELINUX_DISABLED = 0
+SELINUX_ENFORCING = 1
+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
+KS_SHUTDOWN = 2
+
+KS_INSTKEY_SKIP = -99
+
+BOOTPROTO_DHCP = "dhcp"
+BOOTPROTO_BOOTP = "bootp"
+BOOTPROTO_STATIC = "static"
+BOOTPROTO_QUERY = "query"
+BOOTPROTO_IBFT = "ibft"
+
+GROUP_REQUIRED = 0
+GROUP_DEFAULT = 1
+GROUP_ALL = 2
--- /dev/null
+#
+# errors.py: Kickstart error handling.
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+"""
+Error handling classes and functions.
+
+This module exports a single function:
+
+ formatErrorMsg - Properly formats an error message.
+
+It also exports several exception classes:
+
+ KickstartError - A generic exception class.
+
+ KickstartParseError - An exception for errors relating to parsing.
+
+ KickstartValueError - An exception for errors relating to option
+ processing.
+
+ KickstartVersionError - An exception for errors relating to unsupported
+ syntax versions.
+"""
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+def formatErrorMsg(lineno, msg=""):
+ """Properly format the error message msg for inclusion in an exception."""
+ if msg != "":
+ mapping = {"lineno": lineno, "msg": msg}
+ return _("The following problem occurred on line %(lineno)s of the kickstart file:\n\n%(msg)s\n") % mapping
+ else:
+ return _("There was a problem reading from line %s of the kickstart file") % lineno
+
+class KickstartError(Exception):
+ """A generic exception class for unspecific error conditions."""
+ def __init__(self, val = ""):
+ """Create a new KickstartError exception instance with the descriptive
+ message val. val should be the return value of formatErrorMsg.
+ """
+ Exception.__init__(self)
+ self.value = val
+
+ def __str__ (self):
+ return self.value
+
+class KickstartParseError(KickstartError):
+ """An exception class for errors when processing the input file, such as
+ unknown options, commands, or sections.
+ """
+ def __init__(self, msg):
+ """Create a new KickstartParseError exception instance with the
+ descriptive message val. val should be the return value of
+ formatErrorMsg.
+ """
+ KickstartError.__init__(self, msg)
+
+ def __str__(self):
+ return self.value
+
+class KickstartValueError(KickstartError):
+ """An exception class for errors when processing arguments to commands,
+ such as too many arguments, too few arguments, or missing required
+ arguments.
+ """
+ def __init__(self, msg):
+ """Create a new KickstartValueError exception instance with the
+ descriptive message val. val should be the return value of
+ formatErrorMsg.
+ """
+ KickstartError.__init__(self, msg)
+
+ def __str__ (self):
+ return self.value
+
+class KickstartVersionError(KickstartError):
+ """An exception class for errors related to using an incorrect version of
+ kickstart syntax.
+ """
+ def __init__(self, msg):
+ """Create a new KickstartVersionError exception instance with the
+ descriptive message val. val should be the return value of
+ formatErrorMsg.
+ """
+ KickstartError.__init__(self, msg)
+
+ def __str__ (self):
+ return self.value
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2007, 2008, 2009, 2010 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+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
+# to the class that handles it. This is an onto mapping - that is, multiple
+# command names can map to the same class. However, the Handler will ensure
+# that only one instance of each class ever exists.
+commandMap = {
+ FC3: {
+ "auth": authconfig.FC3_Authconfig,
+ "authconfig": authconfig.FC3_Authconfig,
+ "autopart": autopart.FC3_AutoPart,
+ "autostep": autostep.FC3_AutoStep,
+ "bootloader": bootloader.FC3_Bootloader,
+ "cdrom": method.FC3_Method,
+ "clearpart": clearpart.FC3_ClearPart,
+ "cmdline": displaymode.FC3_DisplayMode,
+ "device": device.FC3_Device,
+ "deviceprobe": deviceprobe.FC3_DeviceProbe,
+ "driverdisk": driverdisk.FC3_DriverDisk,
+ "firewall": firewall.FC3_Firewall,
+ "firstboot": firstboot.FC3_Firstboot,
+ "graphical": displaymode.FC3_DisplayMode,
+ "halt": reboot.FC3_Reboot,
+ "harddrive": method.FC3_Method,
+ "ignoredisk": ignoredisk.FC3_IgnoreDisk,
+ "install": upgrade.FC3_Upgrade,
+ "interactive": interactive.FC3_Interactive,
+ "keyboard": keyboard.FC3_Keyboard,
+ "lang": lang.FC3_Lang,
+ "langsupport": langsupport.FC3_LangSupport,
+ "lilo": bootloader.FC3_Bootloader,
+ "lilocheck": lilocheck.FC3_LiloCheck,
+ "logvol": logvol.FC3_LogVol,
+ "monitor": monitor.FC3_Monitor,
+ "mouse": mouse.FC3_Mouse,
+ "network": network.FC3_Network,
+ "nfs": method.FC3_Method,
+ "part": partition.FC3_Partition,
+ "partition": partition.FC3_Partition,
+ "poweroff": reboot.FC3_Reboot,
+ "raid": raid.FC3_Raid,
+ "reboot": reboot.FC3_Reboot,
+ "rootpw": rootpw.FC3_RootPw,
+ "selinux": selinux.FC3_SELinux,
+ "shutdown": reboot.FC3_Reboot,
+ "skipx": skipx.FC3_SkipX,
+ "text": displaymode.FC3_DisplayMode,
+ "timezone": timezone.FC3_Timezone,
+ "upgrade": upgrade.FC3_Upgrade,
+ "url": method.FC3_Method,
+ "vnc": vnc.FC3_Vnc,
+ "volgroup": volgroup.FC3_VolGroup,
+ "xconfig": xconfig.FC3_XConfig,
+ "zerombr": zerombr.FC3_ZeroMbr,
+ "zfcp": zfcp.FC3_ZFCP,
+ },
+
+ # based on fc3
+ FC4: {
+ "auth": authconfig.FC3_Authconfig,
+ "authconfig": authconfig.FC3_Authconfig,
+ "autopart": autopart.FC3_AutoPart,
+ "autostep": autostep.FC3_AutoStep,
+ "bootloader": bootloader.FC4_Bootloader,
+ "cdrom": method.FC3_Method,
+ "clearpart": clearpart.FC3_ClearPart,
+ "cmdline": displaymode.FC3_DisplayMode,
+ "device": device.FC3_Device,
+ "deviceprobe": deviceprobe.FC3_DeviceProbe,
+ "driverdisk": driverdisk.FC4_DriverDisk,
+ "firewall": firewall.FC3_Firewall,
+ "firstboot": firstboot.FC3_Firstboot,
+ "graphical": displaymode.FC3_DisplayMode,
+ "halt": reboot.FC3_Reboot,
+ "harddrive": method.FC3_Method,
+ "ignoredisk": ignoredisk.FC3_IgnoreDisk,
+ "install": upgrade.FC3_Upgrade,
+ "interactive": interactive.FC3_Interactive,
+ "keyboard": keyboard.FC3_Keyboard,
+ "lang": lang.FC3_Lang,
+ "langsupport": langsupport.FC3_LangSupport,
+ "logvol": logvol.FC4_LogVol,
+ "mediacheck": mediacheck.FC4_MediaCheck,
+ "monitor": monitor.FC3_Monitor,
+ "mouse": mouse.FC3_Mouse,
+ "network": network.FC4_Network,
+ "nfs": method.FC3_Method,
+ "part": partition.FC4_Partition,
+ "partition": partition.FC4_Partition,
+ "poweroff": reboot.FC3_Reboot,
+ "raid": raid.FC4_Raid,
+ "reboot": reboot.FC3_Reboot,
+ "rootpw": rootpw.FC3_RootPw,
+ "selinux": selinux.FC3_SELinux,
+ "shutdown": reboot.FC3_Reboot,
+ "skipx": skipx.FC3_SkipX,
+ "text": displaymode.FC3_DisplayMode,
+ "timezone": timezone.FC3_Timezone,
+ "upgrade": upgrade.FC3_Upgrade,
+ "url": method.FC3_Method,
+ "vnc": vnc.FC3_Vnc,
+ "volgroup": volgroup.FC3_VolGroup,
+ "xconfig": xconfig.FC3_XConfig,
+ "zerombr": zerombr.FC3_ZeroMbr,
+ "zfcp": zfcp.FC3_ZFCP,
+ },
+
+ # based on fc4
+ FC5: {
+ "auth": authconfig.FC3_Authconfig,
+ "authconfig": authconfig.FC3_Authconfig,
+ "autopart": autopart.FC3_AutoPart,
+ "autostep": autostep.FC3_AutoStep,
+ "bootloader": bootloader.FC4_Bootloader,
+ "cdrom": method.FC3_Method,
+ "clearpart": clearpart.FC3_ClearPart,
+ "cmdline": displaymode.FC3_DisplayMode,
+ "device": device.FC3_Device,
+ "deviceprobe": deviceprobe.FC3_DeviceProbe,
+ "driverdisk": driverdisk.FC4_DriverDisk,
+ "firewall": firewall.FC3_Firewall,
+ "firstboot": firstboot.FC3_Firstboot,
+ "graphical": displaymode.FC3_DisplayMode,
+ "halt": reboot.FC3_Reboot,
+ "harddrive": method.FC3_Method,
+ "ignoredisk": ignoredisk.FC3_IgnoreDisk,
+ "install": upgrade.FC3_Upgrade,
+ "interactive": interactive.FC3_Interactive,
+ "keyboard": keyboard.FC3_Keyboard,
+ "lang": lang.FC3_Lang,
+ "langsupport": langsupport.FC5_LangSupport,
+ "logvol": logvol.FC4_LogVol,
+ "mediacheck": mediacheck.FC4_MediaCheck,
+ "monitor": monitor.FC3_Monitor,
+ "mouse": mouse.FC3_Mouse,
+ "network": network.FC4_Network,
+ "nfs": method.FC3_Method,
+ "part": partition.FC4_Partition,
+ "partition": partition.FC4_Partition,
+ "poweroff": reboot.FC3_Reboot,
+ "raid": raid.FC5_Raid,
+ "reboot": reboot.FC3_Reboot,
+ "rootpw": rootpw.FC3_RootPw,
+ "selinux": selinux.FC3_SELinux,
+ "shutdown": reboot.FC3_Reboot,
+ "skipx": skipx.FC3_SkipX,
+ "text": displaymode.FC3_DisplayMode,
+ "timezone": timezone.FC3_Timezone,
+ "upgrade": upgrade.FC3_Upgrade,
+ "url": method.FC3_Method,
+ "vnc": vnc.FC3_Vnc,
+ "volgroup": volgroup.FC3_VolGroup,
+ "xconfig": xconfig.FC3_XConfig,
+ "zerombr": zerombr.FC3_ZeroMbr,
+ "zfcp": zfcp.FC3_ZFCP,
+ },
+
+ # based on fc5
+ FC6: {
+ "auth": authconfig.FC3_Authconfig,
+ "authconfig": authconfig.FC3_Authconfig,
+ "autopart": autopart.FC3_AutoPart,
+ "autostep": autostep.FC3_AutoStep,
+ "bootloader": bootloader.FC4_Bootloader,
+ "cdrom": method.FC6_Method,
+ "clearpart": clearpart.FC3_ClearPart,
+ "cmdline": displaymode.FC3_DisplayMode,
+ "device": device.FC3_Device,
+ "deviceprobe": deviceprobe.FC3_DeviceProbe,
+ "dmraid": dmraid.FC6_DmRaid,
+ "driverdisk": driverdisk.FC4_DriverDisk,
+ "firewall": firewall.FC3_Firewall,
+ "firstboot": firstboot.FC3_Firstboot,
+ "graphical": displaymode.FC3_DisplayMode,
+ "halt": reboot.FC6_Reboot,
+ "harddrive": method.FC6_Method,
+ "ignoredisk": ignoredisk.FC3_IgnoreDisk,
+ "install": upgrade.FC3_Upgrade,
+ "interactive": interactive.FC3_Interactive,
+ "iscsi": iscsi.FC6_Iscsi,
+ "iscsiname": iscsiname.FC6_IscsiName,
+ "keyboard": keyboard.FC3_Keyboard,
+ "lang": lang.FC3_Lang,
+ "langsupport": langsupport.FC5_LangSupport,
+ "logging": logging.FC6_Logging,
+ "logvol": logvol.FC4_LogVol,
+ "mediacheck": mediacheck.FC4_MediaCheck,
+ "monitor": monitor.FC6_Monitor,
+ "mouse": mouse.FC3_Mouse,
+ "multipath": multipath.FC6_MultiPath,
+ "network": network.FC6_Network,
+ "nfs": method.FC6_Method,
+ "part": partition.FC4_Partition,
+ "partition": partition.FC4_Partition,
+ "poweroff": reboot.FC6_Reboot,
+ "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,
+ "shutdown": reboot.FC6_Reboot,
+ "skipx": skipx.FC3_SkipX,
+ "text": displaymode.FC3_DisplayMode,
+ "timezone": timezone.FC6_Timezone,
+ "upgrade": upgrade.FC3_Upgrade,
+ "user": user.FC6_User,
+ "url": method.FC6_Method,
+ "vnc": vnc.FC6_Vnc,
+ "volgroup": volgroup.FC3_VolGroup,
+ "xconfig": xconfig.FC6_XConfig,
+ "zerombr": zerombr.FC3_ZeroMbr,
+ "zfcp": zfcp.FC3_ZFCP,
+ },
+
+ # based on fc6
+ F7: {
+ "auth": authconfig.FC3_Authconfig,
+ "authconfig": authconfig.FC3_Authconfig,
+ "autopart": autopart.FC3_AutoPart,
+ "autostep": autostep.FC3_AutoStep,
+ "bootloader": bootloader.FC4_Bootloader,
+ "cdrom": method.FC6_Method,
+ "clearpart": clearpart.FC3_ClearPart,
+ "cmdline": displaymode.FC3_DisplayMode,
+ "device": device.FC3_Device,
+ "deviceprobe": deviceprobe.FC3_DeviceProbe,
+ "dmraid": dmraid.FC6_DmRaid,
+ "driverdisk": driverdisk.FC4_DriverDisk,
+ "firewall": firewall.FC3_Firewall,
+ "firstboot": firstboot.FC3_Firstboot,
+ "graphical": displaymode.FC3_DisplayMode,
+ "halt": reboot.FC6_Reboot,
+ "harddrive": method.FC6_Method,
+ "ignoredisk": ignoredisk.FC3_IgnoreDisk,
+ "install": upgrade.FC3_Upgrade,
+ "interactive": interactive.FC3_Interactive,
+ "iscsi": iscsi.FC6_Iscsi,
+ "iscsiname": iscsiname.FC6_IscsiName,
+ "keyboard": keyboard.FC3_Keyboard,
+ "lang": lang.FC3_Lang,
+ "logging": logging.FC6_Logging,
+ "logvol": logvol.FC4_LogVol,
+ "mediacheck": mediacheck.FC4_MediaCheck,
+ "monitor": monitor.FC6_Monitor,
+ "multipath": multipath.FC6_MultiPath,
+ "network": network.FC6_Network,
+ "nfs": method.FC6_Method,
+ "part": partition.FC4_Partition,
+ "partition": partition.FC4_Partition,
+ "poweroff": reboot.FC6_Reboot,
+ "raid": raid.F7_Raid,
+ "reboot": reboot.FC6_Reboot,
+ "repo": repo.FC6_Repo,
+ "rootpw": rootpw.FC3_RootPw,
+ "selinux": selinux.FC3_SELinux,
+ "services": services.FC6_Services,
+ "shutdown": reboot.FC6_Reboot,
+ "skipx": skipx.FC3_SkipX,
+ "text": displaymode.FC3_DisplayMode,
+ "timezone": timezone.FC6_Timezone,
+ "updates": updates.F7_Updates,
+ "upgrade": upgrade.FC3_Upgrade,
+ "url": method.FC6_Method,
+ "user": user.FC6_User,
+ "vnc": vnc.FC6_Vnc,
+ "volgroup": volgroup.FC3_VolGroup,
+ "xconfig": xconfig.FC6_XConfig,
+ "zerombr": zerombr.FC3_ZeroMbr,
+ "zfcp": zfcp.FC3_ZFCP,
+ },
+
+ # based on f7
+ F8: {
+ "auth": authconfig.FC3_Authconfig,
+ "authconfig": authconfig.FC3_Authconfig,
+ "autopart": autopart.FC3_AutoPart,
+ "autostep": autostep.FC3_AutoStep,
+ "bootloader": bootloader.F8_Bootloader,
+ "cdrom": method.FC6_Method,
+ "clearpart": clearpart.FC3_ClearPart,
+ "cmdline": displaymode.FC3_DisplayMode,
+ "device": device.F8_Device,
+ "deviceprobe": deviceprobe.FC3_DeviceProbe,
+ "dmraid": dmraid.FC6_DmRaid,
+ "driverdisk": driverdisk.FC4_DriverDisk,
+ "firewall": firewall.FC3_Firewall,
+ "firstboot": firstboot.FC3_Firstboot,
+ "graphical": displaymode.FC3_DisplayMode,
+ "halt": reboot.FC6_Reboot,
+ "harddrive": method.FC6_Method,
+ "ignoredisk": ignoredisk.F8_IgnoreDisk,
+ "install": upgrade.FC3_Upgrade,
+ "interactive": interactive.FC3_Interactive,
+ "iscsi": iscsi.FC6_Iscsi,
+ "iscsiname": iscsiname.FC6_IscsiName,
+ "keyboard": keyboard.FC3_Keyboard,
+ "lang": lang.FC3_Lang,
+ "logging": logging.FC6_Logging,
+ "logvol": logvol.FC4_LogVol,
+ "mediacheck": mediacheck.FC4_MediaCheck,
+ "monitor": monitor.FC6_Monitor,
+ "multipath": multipath.FC6_MultiPath,
+ "network": network.F8_Network,
+ "nfs": method.FC6_Method,
+ "part": partition.FC4_Partition,
+ "partition": partition.FC4_Partition,
+ "poweroff": reboot.FC6_Reboot,
+ "raid": raid.F7_Raid,
+ "reboot": reboot.FC6_Reboot,
+ "repo": repo.F8_Repo,
+ "rootpw": rootpw.F8_RootPw,
+ "selinux": selinux.FC3_SELinux,
+ "services": services.FC6_Services,
+ "shutdown": reboot.FC6_Reboot,
+ "skipx": skipx.FC3_SkipX,
+ "text": displaymode.FC3_DisplayMode,
+ "timezone": timezone.FC6_Timezone,
+ "updates": updates.F7_Updates,
+ "upgrade": upgrade.FC3_Upgrade,
+ "url": method.FC6_Method,
+ "user": user.F8_User,
+ "vnc": vnc.FC6_Vnc,
+ "volgroup": volgroup.FC3_VolGroup,
+ "xconfig": xconfig.FC6_XConfig,
+ "zerombr": zerombr.FC3_ZeroMbr,
+ "zfcp": zfcp.FC3_ZFCP,
+ },
+
+ # based on f8
+ F9: {
+ "auth": authconfig.FC3_Authconfig,
+ "authconfig": authconfig.FC3_Authconfig,
+ "autopart": autopart.F9_AutoPart,
+ "autostep": autostep.FC3_AutoStep,
+ "bootloader": bootloader.F8_Bootloader,
+ "cdrom": method.FC6_Method,
+ "clearpart": clearpart.FC3_ClearPart,
+ "cmdline": displaymode.FC3_DisplayMode,
+ "device": device.F8_Device,
+ "deviceprobe": deviceprobe.FC3_DeviceProbe,
+ "dmraid": dmraid.FC6_DmRaid,
+ "driverdisk": driverdisk.FC4_DriverDisk,
+ "firewall": firewall.F9_Firewall,
+ "firstboot": firstboot.FC3_Firstboot,
+ "graphical": displaymode.FC3_DisplayMode,
+ "halt": reboot.FC6_Reboot,
+ "harddrive": method.FC6_Method,
+ "ignoredisk": ignoredisk.F8_IgnoreDisk,
+ "install": upgrade.FC3_Upgrade,
+ "interactive": interactive.FC3_Interactive,
+ "iscsi": iscsi.FC6_Iscsi,
+ "iscsiname": iscsiname.FC6_IscsiName,
+ "keyboard": keyboard.FC3_Keyboard,
+ "lang": lang.FC3_Lang,
+ "logging": logging.FC6_Logging,
+ "logvol": logvol.F9_LogVol,
+ "mediacheck": mediacheck.FC4_MediaCheck,
+ "monitor": monitor.FC6_Monitor,
+ "multipath": multipath.FC6_MultiPath,
+ "network": network.F9_Network,
+ "nfs": method.FC6_Method,
+ "part": partition.F9_Partition,
+ "partition": partition.F9_Partition,
+ "poweroff": reboot.FC6_Reboot,
+ "raid": raid.F9_Raid,
+ "reboot": reboot.FC6_Reboot,
+ "repo": repo.F8_Repo,
+ "rootpw": rootpw.F8_RootPw,
+ "selinux": selinux.FC3_SELinux,
+ "services": services.FC6_Services,
+ "shutdown": reboot.FC6_Reboot,
+ "skipx": skipx.FC3_SkipX,
+ "text": displaymode.FC3_DisplayMode,
+ "timezone": timezone.FC6_Timezone,
+ "updates": updates.F7_Updates,
+ "upgrade": upgrade.FC3_Upgrade,
+ "url": method.FC6_Method,
+ "user": user.F8_User,
+ "vnc": vnc.F9_Vnc,
+ "volgroup": volgroup.FC3_VolGroup,
+ "xconfig": xconfig.F9_XConfig,
+ "zerombr": zerombr.F9_ZeroMbr,
+ "zfcp": zfcp.FC3_ZFCP,
+ },
+
+ # based on f9
+ F10: {
+ "auth": authconfig.FC3_Authconfig,
+ "authconfig": authconfig.FC3_Authconfig,
+ "autopart": autopart.F9_AutoPart,
+ "autostep": autostep.FC3_AutoStep,
+ "bootloader": bootloader.F8_Bootloader,
+ "cdrom": method.FC6_Method,
+ "clearpart": clearpart.FC3_ClearPart,
+ "cmdline": displaymode.FC3_DisplayMode,
+ "device": device.F8_Device,
+ "deviceprobe": deviceprobe.FC3_DeviceProbe,
+ "dmraid": dmraid.FC6_DmRaid,
+ "driverdisk": driverdisk.FC4_DriverDisk,
+ "firewall": firewall.F10_Firewall,
+ "firstboot": firstboot.FC3_Firstboot,
+ "graphical": displaymode.FC3_DisplayMode,
+ "halt": reboot.FC6_Reboot,
+ "harddrive": method.FC6_Method,
+ "ignoredisk": ignoredisk.F8_IgnoreDisk,
+ "install": upgrade.FC3_Upgrade,
+ "interactive": interactive.FC3_Interactive,
+ "iscsi": iscsi.F10_Iscsi,
+ "iscsiname": iscsiname.FC6_IscsiName,
+ "keyboard": keyboard.FC3_Keyboard,
+ "lang": lang.FC3_Lang,
+ "logging": logging.FC6_Logging,
+ "logvol": logvol.F9_LogVol,
+ "mediacheck": mediacheck.FC4_MediaCheck,
+ "monitor": monitor.F10_Monitor,
+ "multipath": multipath.FC6_MultiPath,
+ "network": network.F9_Network,
+ "nfs": method.FC6_Method,
+ "part": partition.F9_Partition,
+ "partition": partition.F9_Partition,
+ "poweroff": reboot.FC6_Reboot,
+ "raid": raid.F9_Raid,
+ "reboot": reboot.FC6_Reboot,
+ "repo": repo.F8_Repo,
+ "rescue": rescue.F10_Rescue,
+ "rootpw": rootpw.F8_RootPw,
+ "selinux": selinux.FC3_SELinux,
+ "services": services.FC6_Services,
+ "shutdown": reboot.FC6_Reboot,
+ "skipx": skipx.FC3_SkipX,
+ "text": displaymode.FC3_DisplayMode,
+ "timezone": timezone.FC6_Timezone,
+ "updates": updates.F7_Updates,
+ "upgrade": upgrade.FC3_Upgrade,
+ "url": method.FC6_Method,
+ "user": user.F8_User,
+ "vnc": vnc.F9_Vnc,
+ "volgroup": volgroup.FC3_VolGroup,
+ "xconfig": xconfig.F10_XConfig,
+ "zerombr": zerombr.F9_ZeroMbr,
+ "zfcp": zfcp.FC3_ZFCP,
+ },
+
+ # based on f10
+ F11: {
+ "auth": authconfig.FC3_Authconfig,
+ "authconfig": authconfig.FC3_Authconfig,
+ "autopart": autopart.F9_AutoPart,
+ "autostep": autostep.FC3_AutoStep,
+ "bootloader": bootloader.F8_Bootloader,
+ "cdrom": method.FC6_Method,
+ "clearpart": clearpart.FC3_ClearPart,
+ "cmdline": displaymode.FC3_DisplayMode,
+ "device": device.F8_Device,
+ "deviceprobe": deviceprobe.FC3_DeviceProbe,
+ "dmraid": dmraid.FC6_DmRaid,
+ "driverdisk": driverdisk.FC4_DriverDisk,
+ "firewall": firewall.F10_Firewall,
+ "firstboot": firstboot.FC3_Firstboot,
+ "graphical": displaymode.FC3_DisplayMode,
+ "halt": reboot.FC6_Reboot,
+ "harddrive": method.FC6_Method,
+ "ignoredisk": ignoredisk.F8_IgnoreDisk,
+ "install": upgrade.F11_Upgrade,
+ "interactive": interactive.FC3_Interactive,
+ "iscsi": iscsi.F10_Iscsi,
+ "iscsiname": iscsiname.FC6_IscsiName,
+ "keyboard": keyboard.FC3_Keyboard,
+ "lang": lang.FC3_Lang,
+ "logging": logging.FC6_Logging,
+ "logvol": logvol.F9_LogVol,
+ "mediacheck": mediacheck.FC4_MediaCheck,
+ "monitor": monitor.F10_Monitor,
+ "multipath": multipath.FC6_MultiPath,
+ "network": network.F9_Network,
+ "nfs": method.FC6_Method,
+ "part": partition.F11_Partition,
+ "partition": partition.F11_Partition,
+ "poweroff": reboot.FC6_Reboot,
+ "raid": raid.F9_Raid,
+ "reboot": reboot.FC6_Reboot,
+ "repo": repo.F11_Repo,
+ "rescue": rescue.F10_Rescue,
+ "rootpw": rootpw.F8_RootPw,
+ "selinux": selinux.FC3_SELinux,
+ "services": services.FC6_Services,
+ "shutdown": reboot.FC6_Reboot,
+ "skipx": skipx.FC3_SkipX,
+ "text": displaymode.FC3_DisplayMode,
+ "timezone": timezone.FC6_Timezone,
+ "updates": updates.F7_Updates,
+ "upgrade": upgrade.F11_Upgrade,
+ "url": method.FC6_Method,
+ "user": user.F8_User,
+ "vnc": vnc.F9_Vnc,
+ "volgroup": volgroup.FC3_VolGroup,
+ "xconfig": xconfig.F10_XConfig,
+ "zerombr": zerombr.F9_ZeroMbr,
+ "zfcp": zfcp.FC3_ZFCP,
+ },
+
+ # based on f11
+ F12: {
+ "auth": authconfig.FC3_Authconfig,
+ "authconfig": authconfig.FC3_Authconfig,
+ "autopart": autopart.F12_AutoPart,
+ "autostep": autostep.FC3_AutoStep,
+ "bootloader": bootloader.F12_Bootloader,
+ "cdrom": method.FC6_Method,
+ "clearpart": clearpart.FC3_ClearPart,
+ "cmdline": displaymode.FC3_DisplayMode,
+ "device": device.F8_Device,
+ "deviceprobe": deviceprobe.FC3_DeviceProbe,
+ "dmraid": dmraid.FC6_DmRaid,
+ "driverdisk": driverdisk.F12_DriverDisk,
+ "fcoe": fcoe.F12_Fcoe,
+ "firewall": firewall.F10_Firewall,
+ "firstboot": firstboot.FC3_Firstboot,
+ "graphical": displaymode.FC3_DisplayMode,
+ "group": group.F12_Group,
+ "halt": reboot.FC6_Reboot,
+ "harddrive": method.FC6_Method,
+ "ignoredisk": ignoredisk.F8_IgnoreDisk,
+ "install": upgrade.F11_Upgrade,
+ "interactive": interactive.FC3_Interactive,
+ "iscsi": iscsi.F10_Iscsi,
+ "iscsiname": iscsiname.FC6_IscsiName,
+ "keyboard": keyboard.FC3_Keyboard,
+ "lang": lang.FC3_Lang,
+ "logging": logging.FC6_Logging,
+ "logvol": logvol.F12_LogVol,
+ "mediacheck": mediacheck.FC4_MediaCheck,
+ "monitor": monitor.F10_Monitor,
+ "multipath": multipath.FC6_MultiPath,
+ "network": network.F9_Network,
+ "nfs": method.FC6_Method,
+ "part": partition.F12_Partition,
+ "partition": partition.F12_Partition,
+ "poweroff": reboot.FC6_Reboot,
+ "raid": raid.F12_Raid,
+ "reboot": reboot.FC6_Reboot,
+ "repo": repo.F11_Repo,
+ "rescue": rescue.F10_Rescue,
+ "rootpw": rootpw.F8_RootPw,
+ "selinux": selinux.FC3_SELinux,
+ "services": services.FC6_Services,
+ "shutdown": reboot.FC6_Reboot,
+ "skipx": skipx.FC3_SkipX,
+ "text": displaymode.FC3_DisplayMode,
+ "timezone": timezone.FC6_Timezone,
+ "updates": updates.F7_Updates,
+ "upgrade": upgrade.F11_Upgrade,
+ "url": method.FC6_Method,
+ "user": user.F12_User,
+ "vnc": vnc.F9_Vnc,
+ "volgroup": volgroup.FC3_VolGroup,
+ "xconfig": xconfig.F10_XConfig,
+ "zerombr": zerombr.F9_ZeroMbr,
+ "zfcp": zfcp.F12_ZFCP,
+ },
+
+ # based on f12
+ F13: {
+ "auth": authconfig.FC3_Authconfig,
+ "authconfig": authconfig.FC3_Authconfig,
+ "autopart": autopart.F12_AutoPart,
+ "autostep": autostep.FC3_AutoStep,
+ "bootloader": bootloader.F12_Bootloader,
+ "cdrom": method.F13_Method,
+ "clearpart": clearpart.FC3_ClearPart,
+ "cmdline": displaymode.FC3_DisplayMode,
+ "device": device.F8_Device,
+ "deviceprobe": deviceprobe.FC3_DeviceProbe,
+ "dmraid": dmraid.FC6_DmRaid,
+ "driverdisk": driverdisk.F12_DriverDisk,
+ "fcoe": fcoe.F13_Fcoe,
+ "firewall": firewall.F10_Firewall,
+ "firstboot": firstboot.FC3_Firstboot,
+ "graphical": displaymode.FC3_DisplayMode,
+ "group": group.F12_Group,
+ "halt": reboot.FC6_Reboot,
+ "harddrive": method.F13_Method,
+ "ignoredisk": ignoredisk.F8_IgnoreDisk,
+ "install": upgrade.F11_Upgrade,
+ "interactive": interactive.FC3_Interactive,
+ "iscsi": iscsi.F10_Iscsi,
+ "iscsiname": iscsiname.FC6_IscsiName,
+ "keyboard": keyboard.FC3_Keyboard,
+ "lang": lang.FC3_Lang,
+ "logging": logging.FC6_Logging,
+ "logvol": logvol.F12_LogVol,
+ "mediacheck": mediacheck.FC4_MediaCheck,
+ "monitor": monitor.F10_Monitor,
+ "multipath": multipath.FC6_MultiPath,
+ "network": network.F9_Network,
+ "nfs": method.F13_Method,
+ "part": partition.F12_Partition,
+ "partition": partition.F12_Partition,
+ "poweroff": reboot.FC6_Reboot,
+ "raid": raid.F13_Raid,
+ "reboot": reboot.FC6_Reboot,
+ "repo": repo.F13_Repo,
+ "rescue": rescue.F10_Rescue,
+ "rootpw": rootpw.F8_RootPw,
+ "selinux": selinux.FC3_SELinux,
+ "services": services.FC6_Services,
+ "shutdown": reboot.FC6_Reboot,
+ "skipx": skipx.FC3_SkipX,
+ "sshpw": sshpw.F13_SshPw,
+ "text": displaymode.FC3_DisplayMode,
+ "timezone": timezone.FC6_Timezone,
+ "updates": updates.F7_Updates,
+ "upgrade": upgrade.F11_Upgrade,
+ "url": method.F13_Method,
+ "user": user.F12_User,
+ "vnc": vnc.F9_Vnc,
+ "volgroup": volgroup.FC3_VolGroup,
+ "xconfig": xconfig.F10_XConfig,
+ "zerombr": zerombr.F9_ZeroMbr,
+ "zfcp": zfcp.F12_ZFCP,
+ },
+
+ # based on f13
+ F14: {
+ "auth": authconfig.FC3_Authconfig,
+ "authconfig": authconfig.FC3_Authconfig,
+ "autopart": autopart.F12_AutoPart,
+ "autostep": autostep.FC3_AutoStep,
+ "bootloader": bootloader.F14_Bootloader,
+ "cdrom": method.F14_Method,
+ "clearpart": clearpart.FC3_ClearPart,
+ "cmdline": displaymode.FC3_DisplayMode,
+ "device": device.F8_Device,
+ "deviceprobe": deviceprobe.FC3_DeviceProbe,
+ "dmraid": dmraid.FC6_DmRaid,
+ "driverdisk": driverdisk.F14_DriverDisk,
+ "fcoe": fcoe.F13_Fcoe,
+ "firewall": firewall.F14_Firewall,
+ "firstboot": firstboot.FC3_Firstboot,
+ "graphical": displaymode.FC3_DisplayMode,
+ "group": group.F12_Group,
+ "halt": reboot.FC6_Reboot,
+ "harddrive": method.F14_Method,
+ "ignoredisk": ignoredisk.F14_IgnoreDisk,
+ "install": upgrade.F11_Upgrade,
+ "interactive": interactive.F14_Interactive,
+ "iscsi": iscsi.F10_Iscsi,
+ "iscsiname": iscsiname.FC6_IscsiName,
+ "keyboard": keyboard.FC3_Keyboard,
+ "lang": lang.FC3_Lang,
+ "logging": logging.FC6_Logging,
+ "logvol": logvol.F14_LogVol,
+ "mediacheck": mediacheck.FC4_MediaCheck,
+ "monitor": monitor.F10_Monitor,
+ "multipath": multipath.FC6_MultiPath,
+ "network": network.F9_Network,
+ "nfs": method.F14_Method,
+ "part": partition.F14_Partition,
+ "partition": partition.F14_Partition,
+ "poweroff": reboot.FC6_Reboot,
+ "raid": raid.F14_Raid,
+ "reboot": reboot.FC6_Reboot,
+ "repo": repo.F14_Repo,
+ "rescue": rescue.F10_Rescue,
+ "rootpw": rootpw.F8_RootPw,
+ "selinux": selinux.FC3_SELinux,
+ "services": services.FC6_Services,
+ "shutdown": reboot.FC6_Reboot,
+ "skipx": skipx.FC3_SkipX,
+ "sshpw": sshpw.F13_SshPw,
+ "text": displaymode.FC3_DisplayMode,
+ "timezone": timezone.FC6_Timezone,
+ "updates": updates.F7_Updates,
+ "upgrade": upgrade.F11_Upgrade,
+ "url": method.F14_Method,
+ "user": user.F12_User,
+ "vnc": vnc.F9_Vnc,
+ "volgroup": volgroup.FC3_VolGroup,
+ "xconfig": xconfig.F14_XConfig,
+ "zerombr": zerombr.F9_ZeroMbr,
+ "zfcp": zfcp.F14_ZFCP,
+ },
+
+ # based on f14
+ F15: {
+ "auth": authconfig.FC3_Authconfig,
+ "authconfig": authconfig.FC3_Authconfig,
+ "autopart": autopart.F12_AutoPart,
+ "autostep": autostep.FC3_AutoStep,
+ "bootloader": bootloader.F15_Bootloader,
+ "cdrom": method.F14_Method,
+ "clearpart": clearpart.FC3_ClearPart,
+ "cmdline": displaymode.FC3_DisplayMode,
+ "device": device.F8_Device,
+ "deviceprobe": deviceprobe.FC3_DeviceProbe,
+ "dmraid": dmraid.FC6_DmRaid,
+ "driverdisk": driverdisk.F14_DriverDisk,
+ "fcoe": fcoe.F13_Fcoe,
+ "firewall": firewall.F14_Firewall,
+ "firstboot": firstboot.FC3_Firstboot,
+ "graphical": displaymode.FC3_DisplayMode,
+ "group": group.F12_Group,
+ "halt": reboot.FC6_Reboot,
+ "harddrive": method.F14_Method,
+ "ignoredisk": ignoredisk.F14_IgnoreDisk,
+ "install": upgrade.F11_Upgrade,
+ "iscsi": iscsi.F10_Iscsi,
+ "iscsiname": iscsiname.FC6_IscsiName,
+ "keyboard": keyboard.FC3_Keyboard,
+ "lang": lang.FC3_Lang,
+ "logging": logging.FC6_Logging,
+ "logvol": logvol.F15_LogVol,
+ "mediacheck": mediacheck.FC4_MediaCheck,
+ "monitor": monitor.F10_Monitor,
+ "multipath": multipath.FC6_MultiPath,
+ "network": network.F9_Network,
+ "nfs": method.F14_Method,
+ "part": partition.F14_Partition,
+ "partition": partition.F14_Partition,
+ "poweroff": reboot.FC6_Reboot,
+ "raid": raid.F15_Raid,
+ "reboot": reboot.FC6_Reboot,
+ "repo": repo.F15_Repo,
+ "rescue": rescue.F10_Rescue,
+ "rootpw": rootpw.F8_RootPw,
+ "selinux": selinux.FC3_SELinux,
+ "services": services.FC6_Services,
+ "shutdown": reboot.FC6_Reboot,
+ "skipx": skipx.FC3_SkipX,
+ "sshpw": sshpw.F13_SshPw,
+ "text": displaymode.FC3_DisplayMode,
+ "timezone": timezone.FC6_Timezone,
+ "updates": updates.F7_Updates,
+ "upgrade": upgrade.F11_Upgrade,
+ "url": method.F14_Method,
+ "user": user.F12_User,
+ "vnc": vnc.F9_Vnc,
+ "volgroup": volgroup.FC3_VolGroup,
+ "xconfig": xconfig.F14_XConfig,
+ "zerombr": zerombr.F9_ZeroMbr,
+ "zfcp": zfcp.F14_ZFCP,
+ },
+
+ # based on f15
+ F16: {
+ "auth": authconfig.FC3_Authconfig,
+ "authconfig": authconfig.FC3_Authconfig,
+ "autopart": autopart.F12_AutoPart,
+ "autostep": autostep.FC3_AutoStep,
+ "bootloader": bootloader.F15_Bootloader,
+ "cdrom": method.F14_Method,
+ "clearpart": clearpart.FC3_ClearPart,
+ "cmdline": displaymode.FC3_DisplayMode,
+ "device": device.F8_Device,
+ "deviceprobe": deviceprobe.FC3_DeviceProbe,
+ "dmraid": dmraid.FC6_DmRaid,
+ "driverdisk": driverdisk.F14_DriverDisk,
+ "fcoe": fcoe.F13_Fcoe,
+ "firewall": firewall.F14_Firewall,
+ "firstboot": firstboot.FC3_Firstboot,
+ "graphical": displaymode.FC3_DisplayMode,
+ "group": group.F12_Group,
+ "halt": reboot.FC6_Reboot,
+ "harddrive": method.F14_Method,
+ "ignoredisk": ignoredisk.F14_IgnoreDisk,
+ "install": upgrade.F11_Upgrade,
+ "iscsi": iscsi.F10_Iscsi,
+ "iscsiname": iscsiname.FC6_IscsiName,
+ "keyboard": keyboard.FC3_Keyboard,
+ "lang": lang.FC3_Lang,
+ "logging": logging.FC6_Logging,
+ "logvol": logvol.F15_LogVol,
+ "mediacheck": mediacheck.FC4_MediaCheck,
+ "monitor": monitor.F10_Monitor,
+ "multipath": multipath.FC6_MultiPath,
+ "network": network.F16_Network,
+ "nfs": method.F14_Method,
+ "part": partition.F14_Partition,
+ "partition": partition.F14_Partition,
+ "poweroff": reboot.FC6_Reboot,
+ "raid": raid.F15_Raid,
+ "reboot": reboot.FC6_Reboot,
+ "repo": repo.F15_Repo,
+ "rescue": rescue.F10_Rescue,
+ "rootpw": rootpw.F8_RootPw,
+ "selinux": selinux.FC3_SELinux,
+ "services": services.FC6_Services,
+ "shutdown": reboot.FC6_Reboot,
+ "skipx": skipx.FC3_SkipX,
+ "sshpw": sshpw.F13_SshPw,
+ "text": displaymode.FC3_DisplayMode,
+ "timezone": timezone.FC6_Timezone,
+ "updates": updates.F7_Updates,
+ "upgrade": upgrade.F11_Upgrade,
+ "url": method.F14_Method,
+ "user": user.F12_User,
+ "vnc": vnc.F9_Vnc,
+ "volgroup": volgroup.FC3_VolGroup,
+ "xconfig": xconfig.F14_XConfig,
+ "zerombr": zerombr.F9_ZeroMbr,
+ "zfcp": zfcp.F14_ZFCP,
+ },
+
+ # based on fc1
+ RHEL3: {
+ "auth": authconfig.FC3_Authconfig,
+ "authconfig": authconfig.FC3_Authconfig,
+ "autopart": autopart.FC3_AutoPart,
+ "autostep": autostep.FC3_AutoStep,
+ "bootloader": bootloader.FC3_Bootloader,
+ "cdrom": method.FC3_Method,
+ "clearpart": clearpart.FC3_ClearPart,
+ "cmdline": displaymode.FC3_DisplayMode,
+ "device": device.FC3_Device,
+ "deviceprobe": deviceprobe.FC3_DeviceProbe,
+ "driverdisk": driverdisk.FC3_DriverDisk,
+ "firewall": firewall.FC3_Firewall,
+ "firstboot": firstboot.FC3_Firstboot,
+ "graphical": displaymode.FC3_DisplayMode,
+ "halt": reboot.FC3_Reboot,
+ "harddrive": method.FC3_Method,
+ "ignoredisk": ignoredisk.FC3_IgnoreDisk,
+ "install": upgrade.FC3_Upgrade,
+ "interactive": interactive.FC3_Interactive,
+ "keyboard": keyboard.FC3_Keyboard,
+ "lang": lang.FC3_Lang,
+ "langsupport": langsupport.FC3_LangSupport,
+ "lilo": bootloader.FC3_Bootloader,
+ "lilocheck": lilocheck.FC3_LiloCheck,
+ "logvol": logvol.FC3_LogVol,
+ "monitor": monitor.FC3_Monitor,
+ "mouse": mouse.RHEL3_Mouse,
+ "network": network.FC3_Network,
+ "nfs": method.FC3_Method,
+ "part": partition.FC3_Partition,
+ "partition": partition.FC3_Partition,
+ "poweroff": reboot.FC3_Reboot,
+ "raid": raid.FC3_Raid,
+ "reboot": reboot.FC3_Reboot,
+ "rootpw": rootpw.FC3_RootPw,
+ "shutdown": reboot.FC3_Reboot,
+ "skipx": skipx.FC3_SkipX,
+ "text": displaymode.FC3_DisplayMode,
+ "timezone": timezone.FC3_Timezone,
+ "upgrade": upgrade.FC3_Upgrade,
+ "url": method.FC3_Method,
+ "vnc": vnc.FC3_Vnc,
+ "volgroup": volgroup.FC3_VolGroup,
+ "xconfig": xconfig.FC3_XConfig,
+ "zerombr": zerombr.FC3_ZeroMbr,
+ },
+
+ # based on fc3
+ RHEL4: {
+ "auth": authconfig.FC3_Authconfig,
+ "authconfig": authconfig.FC3_Authconfig,
+ "autopart": autopart.FC3_AutoPart,
+ "autostep": autostep.FC3_AutoStep,
+ "bootloader": bootloader.FC3_Bootloader,
+ "cdrom": method.FC3_Method,
+ "clearpart": clearpart.FC3_ClearPart,
+ "cmdline": displaymode.FC3_DisplayMode,
+ "device": device.FC3_Device,
+ "deviceprobe": deviceprobe.FC3_DeviceProbe,
+ "driverdisk": driverdisk.FC4_DriverDisk,
+ "firewall": firewall.FC3_Firewall,
+ "firstboot": firstboot.FC3_Firstboot,
+ "graphical": displaymode.FC3_DisplayMode,
+ "halt": reboot.FC3_Reboot,
+ "harddrive": method.FC3_Method,
+ "ignoredisk": ignoredisk.F8_IgnoreDisk,
+ "install": upgrade.FC3_Upgrade,
+ "interactive": interactive.FC3_Interactive,
+ "keyboard": keyboard.FC3_Keyboard,
+ "lang": lang.FC3_Lang,
+ "langsupport": langsupport.FC3_LangSupport,
+ "lilo": bootloader.FC3_Bootloader,
+ "lilocheck": lilocheck.FC3_LiloCheck,
+ "logvol": logvol.FC3_LogVol,
+ "monitor": monitor.FC3_Monitor,
+ "mouse": mouse.FC3_Mouse,
+ "network": network.RHEL4_Network,
+ "nfs": method.FC3_Method,
+ "part": partition.FC3_Partition,
+ "partition": partition.FC3_Partition,
+ "poweroff": reboot.FC3_Reboot,
+ "raid": raid.FC3_Raid,
+ "reboot": reboot.FC3_Reboot,
+ "rootpw": rootpw.FC3_RootPw,
+ "selinux": selinux.FC3_SELinux,
+ "shutdown": reboot.FC3_Reboot,
+ "skipx": skipx.FC3_SkipX,
+ "text": displaymode.FC3_DisplayMode,
+ "timezone": timezone.FC3_Timezone,
+ "upgrade": upgrade.FC3_Upgrade,
+ "url": method.FC3_Method,
+ "vnc": vnc.FC3_Vnc,
+ "volgroup": volgroup.FC3_VolGroup,
+ "xconfig": xconfig.FC3_XConfig,
+ "zerombr": zerombr.FC3_ZeroMbr,
+ "zfcp": zfcp.FC3_ZFCP,
+ },
+
+ # based on fc6
+ RHEL5: {
+ "auth": authconfig.FC3_Authconfig,
+ "authconfig": authconfig.FC3_Authconfig,
+ "autopart": autopart.F9_AutoPart,
+ "autostep": autostep.FC3_AutoStep,
+ "bootloader": bootloader.RHEL5_Bootloader,
+ "cdrom": method.FC6_Method,
+ "clearpart": clearpart.FC3_ClearPart,
+ "cmdline": displaymode.FC3_DisplayMode,
+ "device": device.FC3_Device,
+ "deviceprobe": deviceprobe.FC3_DeviceProbe,
+ "dmraid": dmraid.FC6_DmRaid,
+ "driverdisk": driverdisk.F12_DriverDisk,
+ "firewall": firewall.FC3_Firewall,
+ "firstboot": firstboot.FC3_Firstboot,
+ "graphical": displaymode.FC3_DisplayMode,
+ "halt": reboot.FC6_Reboot,
+ "harddrive": method.FC6_Method,
+ "ignoredisk": ignoredisk.F8_IgnoreDisk,
+ "install": upgrade.FC3_Upgrade,
+ "interactive": interactive.FC3_Interactive,
+ "iscsi": iscsi.FC6_Iscsi,
+ "iscsiname": iscsiname.FC6_IscsiName,
+ "key": key.RHEL5_Key,
+ "keyboard": keyboard.FC3_Keyboard,
+ "lang": lang.FC3_Lang,
+ "langsupport": langsupport.FC5_LangSupport,
+ "logging": logging.FC6_Logging,
+ "logvol": logvol.RHEL5_LogVol,
+ "mediacheck": mediacheck.FC4_MediaCheck,
+ "monitor": monitor.FC6_Monitor,
+ "mouse": mouse.FC3_Mouse,
+ "multipath": multipath.FC6_MultiPath,
+ "network": network.RHEL5_Network,
+ "nfs": method.FC6_Method,
+ "part": partition.RHEL5_Partition,
+ "partition": partition.RHEL5_Partition,
+ "poweroff": reboot.FC6_Reboot,
+ "raid": raid.RHEL5_Raid,
+ "reboot": reboot.FC6_Reboot,
+ "repo": repo.FC6_Repo,
+ "rootpw": rootpw.FC3_RootPw,
+ "services": services.FC6_Services,
+ "selinux": selinux.FC3_SELinux,
+ "shutdown": reboot.FC6_Reboot,
+ "skipx": skipx.FC3_SkipX,
+ "text": displaymode.FC3_DisplayMode,
+ "timezone": timezone.FC6_Timezone,
+ "upgrade": upgrade.FC3_Upgrade,
+ "user": user.FC6_User,
+ "url": method.FC6_Method,
+ "vnc": vnc.FC6_Vnc,
+ "volgroup": volgroup.FC3_VolGroup,
+ "xconfig": xconfig.FC6_XConfig,
+ "zerombr": zerombr.FC3_ZeroMbr,
+ "zfcp": zfcp.FC3_ZFCP,
+ },
+
+ # based on f13ish
+ RHEL6: {
+ "auth": authconfig.FC3_Authconfig,
+ "authconfig": authconfig.FC3_Authconfig,
+ "autopart": autopart.F12_AutoPart,
+ "autostep": autostep.FC3_AutoStep,
+ "bootloader": bootloader.RHEL6_Bootloader,
+ "cdrom": method.RHEL6_Method,
+ "clearpart": clearpart.FC3_ClearPart,
+ "cmdline": displaymode.FC3_DisplayMode,
+ "device": device.F8_Device,
+ "deviceprobe": deviceprobe.FC3_DeviceProbe,
+ "dmraid": dmraid.FC6_DmRaid,
+ "driverdisk": driverdisk.F12_DriverDisk,
+ "fcoe": fcoe.F13_Fcoe,
+ "firewall": firewall.F10_Firewall,
+ "firstboot": firstboot.FC3_Firstboot,
+ "graphical": displaymode.FC3_DisplayMode,
+ "group": group.F12_Group,
+ "halt": reboot.FC6_Reboot,
+ "harddrive": method.RHEL6_Method,
+ "ignoredisk": ignoredisk.RHEL6_IgnoreDisk,
+ "install": upgrade.F11_Upgrade,
+ "interactive": interactive.FC3_Interactive,
+ "iscsi": iscsi.F10_Iscsi,
+ "iscsiname": iscsiname.FC6_IscsiName,
+ "keyboard": keyboard.FC3_Keyboard,
+ "lang": lang.FC3_Lang,
+ "logging": logging.FC6_Logging,
+ "logvol": logvol.F12_LogVol,
+ "mediacheck": mediacheck.FC4_MediaCheck,
+ "monitor": monitor.F10_Monitor,
+ "multipath": multipath.FC6_MultiPath,
+ "network": network.RHEL6_Network,
+ "nfs": method.RHEL6_Method,
+ "part": partition.F12_Partition,
+ "partition": partition.F12_Partition,
+ "poweroff": reboot.FC6_Reboot,
+ "raid": raid.F13_Raid,
+ "reboot": reboot.FC6_Reboot,
+ "repo": repo.RHEL6_Repo,
+ "rescue": rescue.F10_Rescue,
+ "rootpw": rootpw.F8_RootPw,
+ "selinux": selinux.FC3_SELinux,
+ "services": services.FC6_Services,
+ "shutdown": reboot.FC6_Reboot,
+ "skipx": skipx.FC3_SkipX,
+ "sshpw": sshpw.F13_SshPw,
+ "text": displaymode.FC3_DisplayMode,
+ "timezone": timezone.FC6_Timezone,
+ "updates": updates.F7_Updates,
+ "upgrade": upgrade.F11_Upgrade,
+ "url": method.RHEL6_Method,
+ "user": user.F12_User,
+ "vnc": vnc.F9_Vnc,
+ "volgroup": volgroup.FC3_VolGroup,
+ "xconfig": xconfig.F10_XConfig,
+ "zerombr": zerombr.F9_ZeroMbr,
+ "zfcp": zfcp.F12_ZFCP,
+ }
+}
+
+# This map is keyed on kickstart syntax version as provided by
+# pykickstart.version. Within each sub-dict is a mapping from a data object
+# name to the class that provides it. This is a bijective mapping - that is,
+# each name maps to exactly one data class and all data classes have a name.
+# More than one instance of each class is allowed to exist, however.
+dataMap = {
+ FC3: {
+ "DriverDiskData": driverdisk.FC3_DriverDiskData,
+ "LogVolData": logvol.FC3_LogVolData,
+ "NetworkData": network.FC3_NetworkData,
+ "PartData": partition.FC3_PartData,
+ "RaidData": raid.FC3_RaidData,
+ "VolGroupData": volgroup.FC3_VolGroupData,
+ "ZFCPData": zfcp.FC3_ZFCPData,
+ },
+ FC4: {
+ "DriverDiskData": driverdisk.FC4_DriverDiskData,
+ "LogVolData": logvol.FC4_LogVolData,
+ "NetworkData": network.FC4_NetworkData,
+ "PartData": partition.FC4_PartData,
+ "RaidData": raid.FC4_RaidData,
+ "VolGroupData": volgroup.FC3_VolGroupData,
+ "ZFCPData": zfcp.FC3_ZFCPData,
+ },
+ FC5: {
+ "DriverDiskData": driverdisk.FC4_DriverDiskData,
+ "LogVolData": logvol.FC4_LogVolData,
+ "NetworkData": network.FC4_NetworkData,
+ "PartData": partition.FC4_PartData,
+ "RaidData": raid.FC5_RaidData,
+ "VolGroupData": volgroup.FC3_VolGroupData,
+ "ZFCPData": zfcp.FC3_ZFCPData,
+ },
+ FC6: {
+ "DriverDiskData": driverdisk.FC4_DriverDiskData,
+ "DmRaidData": dmraid.FC6_DmRaidData,
+ "IscsiData": iscsi.FC6_IscsiData,
+ "LogVolData": logvol.FC4_LogVolData,
+ "MultiPathData": multipath.FC6_MultiPathData,
+ "NetworkData": network.FC6_NetworkData,
+ "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,
+ },
+ F7: {
+ "DriverDiskData": driverdisk.FC4_DriverDiskData,
+ "DmRaidData": dmraid.FC6_DmRaidData,
+ "IscsiData": iscsi.FC6_IscsiData,
+ "LogVolData": logvol.FC4_LogVolData,
+ "MultiPathData": multipath.FC6_MultiPathData,
+ "NetworkData": network.FC6_NetworkData,
+ "PartData": partition.FC4_PartData,
+ "RaidData": raid.F7_RaidData,
+ "RepoData": repo.FC6_RepoData,
+ "UserData": user.FC6_UserData,
+ "VolGroupData": volgroup.FC3_VolGroupData,
+ "ZFCPData": zfcp.FC3_ZFCPData,
+ },
+ F8: {
+ "DriverDiskData": driverdisk.FC4_DriverDiskData,
+ "DeviceData": device.F8_DeviceData,
+ "DmRaidData": dmraid.FC6_DmRaidData,
+ "IscsiData": iscsi.FC6_IscsiData,
+ "LogVolData": logvol.FC4_LogVolData,
+ "MultiPathData": multipath.FC6_MultiPathData,
+ "NetworkData": network.F8_NetworkData,
+ "PartData": partition.FC4_PartData,
+ "RaidData": raid.F7_RaidData,
+ "RepoData": repo.F8_RepoData,
+ "UserData": user.F8_UserData,
+ "VolGroupData": volgroup.FC3_VolGroupData,
+ "ZFCPData": zfcp.FC3_ZFCPData,
+ },
+ F9: {
+ "DriverDiskData": driverdisk.FC4_DriverDiskData,
+ "DeviceData": device.F8_DeviceData,
+ "DmRaidData": dmraid.FC6_DmRaidData,
+ "IscsiData": iscsi.FC6_IscsiData,
+ "LogVolData": logvol.F9_LogVolData,
+ "MultiPathData": multipath.FC6_MultiPathData,
+ "NetworkData": network.F8_NetworkData,
+ "PartData": partition.F9_PartData,
+ "RaidData": raid.F9_RaidData,
+ "RepoData": repo.F8_RepoData,
+ "UserData": user.F8_UserData,
+ "VolGroupData": volgroup.FC3_VolGroupData,
+ "ZFCPData": zfcp.FC3_ZFCPData,
+ },
+ F10: {
+ "DriverDiskData": driverdisk.FC4_DriverDiskData,
+ "DeviceData": device.F8_DeviceData,
+ "DmRaidData": dmraid.FC6_DmRaidData,
+ "IscsiData": iscsi.F10_IscsiData,
+ "LogVolData": logvol.F9_LogVolData,
+ "MultiPathData": multipath.FC6_MultiPathData,
+ "NetworkData": network.F8_NetworkData,
+ "PartData": partition.F9_PartData,
+ "RaidData": raid.F9_RaidData,
+ "RepoData": repo.F8_RepoData,
+ "UserData": user.F8_UserData,
+ "VolGroupData": volgroup.FC3_VolGroupData,
+ "ZFCPData": zfcp.FC3_ZFCPData,
+ },
+ F11: {
+ "DriverDiskData": driverdisk.FC4_DriverDiskData,
+ "DeviceData": device.F8_DeviceData,
+ "DmRaidData": dmraid.FC6_DmRaidData,
+ "IscsiData": iscsi.F10_IscsiData,
+ "LogVolData": logvol.F9_LogVolData,
+ "MultiPathData": multipath.FC6_MultiPathData,
+ "NetworkData": network.F8_NetworkData,
+ "PartData": partition.F11_PartData,
+ "RaidData": raid.F9_RaidData,
+ "RepoData": repo.F11_RepoData,
+ "UserData": user.F8_UserData,
+ "VolGroupData": volgroup.FC3_VolGroupData,
+ "ZFCPData": zfcp.FC3_ZFCPData,
+ },
+ F12: {
+ "DriverDiskData": driverdisk.F12_DriverDiskData,
+ "DeviceData": device.F8_DeviceData,
+ "DmRaidData": dmraid.FC6_DmRaidData,
+ "FcoeData": fcoe.F12_FcoeData,
+ "GroupData": group.F12_GroupData,
+ "IscsiData": iscsi.F10_IscsiData,
+ "LogVolData": logvol.F12_LogVolData,
+ "MultiPathData": multipath.FC6_MultiPathData,
+ "NetworkData": network.F8_NetworkData,
+ "PartData": partition.F12_PartData,
+ "RaidData": raid.F12_RaidData,
+ "RepoData": repo.F11_RepoData,
+ "UserData": user.F12_UserData,
+ "VolGroupData": volgroup.FC3_VolGroupData,
+ "ZFCPData": zfcp.F12_ZFCPData,
+ },
+ F13: {
+ "DriverDiskData": driverdisk.F12_DriverDiskData,
+ "DeviceData": device.F8_DeviceData,
+ "DmRaidData": dmraid.FC6_DmRaidData,
+ "FcoeData": fcoe.F13_FcoeData,
+ "GroupData": group.F12_GroupData,
+ "IscsiData": iscsi.F10_IscsiData,
+ "LogVolData": logvol.F12_LogVolData,
+ "MultiPathData": multipath.FC6_MultiPathData,
+ "NetworkData": network.F8_NetworkData,
+ "PartData": partition.F12_PartData,
+ "RaidData": raid.F13_RaidData,
+ "RepoData": repo.F13_RepoData,
+ "SshPwData": sshpw.F13_SshPwData,
+ "UserData": user.F12_UserData,
+ "VolGroupData": volgroup.FC3_VolGroupData,
+ "ZFCPData": zfcp.F12_ZFCPData,
+ },
+ F14: {
+ "DriverDiskData": driverdisk.F14_DriverDiskData,
+ "DeviceData": device.F8_DeviceData,
+ "DmRaidData": dmraid.FC6_DmRaidData,
+ "FcoeData": fcoe.F13_FcoeData,
+ "GroupData": group.F12_GroupData,
+ "IscsiData": iscsi.F10_IscsiData,
+ "LogVolData": logvol.F14_LogVolData,
+ "MultiPathData": multipath.FC6_MultiPathData,
+ "NetworkData": network.F8_NetworkData,
+ "PartData": partition.F14_PartData,
+ "RaidData": raid.F14_RaidData,
+ "RepoData": repo.F14_RepoData,
+ "SshPwData": sshpw.F13_SshPwData,
+ "UserData": user.F12_UserData,
+ "VolGroupData": volgroup.FC3_VolGroupData,
+ "ZFCPData": zfcp.F14_ZFCPData,
+ },
+ F15: {
+ "DriverDiskData": driverdisk.F14_DriverDiskData,
+ "DeviceData": device.F8_DeviceData,
+ "DmRaidData": dmraid.FC6_DmRaidData,
+ "FcoeData": fcoe.F13_FcoeData,
+ "GroupData": group.F12_GroupData,
+ "IscsiData": iscsi.F10_IscsiData,
+ "LogVolData": logvol.F15_LogVolData,
+ "MultiPathData": multipath.FC6_MultiPathData,
+ "NetworkData": network.F8_NetworkData,
+ "PartData": partition.F14_PartData,
+ "RaidData": raid.F15_RaidData,
+ "RepoData": repo.F15_RepoData,
+ "SshPwData": sshpw.F13_SshPwData,
+ "UserData": user.F12_UserData,
+ "VolGroupData": volgroup.FC3_VolGroupData,
+ "ZFCPData": zfcp.F14_ZFCPData,
+ },
+ F16: {
+ "DriverDiskData": driverdisk.F14_DriverDiskData,
+ "DeviceData": device.F8_DeviceData,
+ "DmRaidData": dmraid.FC6_DmRaidData,
+ "FcoeData": fcoe.F13_FcoeData,
+ "GroupData": group.F12_GroupData,
+ "IscsiData": iscsi.F10_IscsiData,
+ "LogVolData": logvol.F15_LogVolData,
+ "MultiPathData": multipath.FC6_MultiPathData,
+ "NetworkData": network.F16_NetworkData,
+ "PartData": partition.F14_PartData,
+ "RaidData": raid.F15_RaidData,
+ "RepoData": repo.F15_RepoData,
+ "SshPwData": sshpw.F13_SshPwData,
+ "UserData": user.F12_UserData,
+ "VolGroupData": volgroup.FC3_VolGroupData,
+ "ZFCPData": zfcp.F14_ZFCPData,
+ },
+ RHEL3: {
+ "DriverDiskData": driverdisk.FC3_DriverDiskData,
+ "LogVolData": logvol.FC3_LogVolData,
+ "NetworkData": network.RHEL4_NetworkData,
+ "PartData": partition.FC3_PartData,
+ "RaidData": raid.FC3_RaidData,
+ "VolGroupData": volgroup.FC3_VolGroupData,
+ "ZFCPData": zfcp.FC3_ZFCPData,
+ },
+ RHEL4: {
+ "DriverDiskData": driverdisk.FC4_DriverDiskData,
+ "LogVolData": logvol.FC3_LogVolData,
+ "NetworkData": network.RHEL4_NetworkData,
+ "PartData": partition.FC3_PartData,
+ "RaidData": raid.FC3_RaidData,
+ "VolGroupData": volgroup.FC3_VolGroupData,
+ "ZFCPData": zfcp.FC3_ZFCPData,
+ },
+ RHEL5: {
+ "DriverDiskData": driverdisk.F12_DriverDiskData,
+ "DmRaidData": dmraid.FC6_DmRaidData,
+ "IscsiData": iscsi.FC6_IscsiData,
+ "LogVolData": logvol.RHEL5_LogVolData,
+ "MultiPathData": multipath.FC6_MultiPathData,
+ "NetworkData": network.FC6_NetworkData,
+ "PartData": partition.RHEL5_PartData,
+ "RaidData": raid.RHEL5_RaidData,
+ "RepoData": repo.FC6_RepoData,
+ "UserData": user.FC6_UserData,
+ "VolGroupData": volgroup.FC3_VolGroupData,
+ "ZFCPData": zfcp.FC3_ZFCPData,
+ },
+ RHEL6: {
+ "DriverDiskData": driverdisk.F12_DriverDiskData,
+ "DeviceData": device.F8_DeviceData,
+ "DmRaidData": dmraid.FC6_DmRaidData,
+ "FcoeData": fcoe.F13_FcoeData,
+ "GroupData": group.F12_GroupData,
+ "IscsiData": iscsi.F10_IscsiData,
+ "LogVolData": logvol.F12_LogVolData,
+ "MultiPathData": multipath.FC6_MultiPathData,
+ "NetworkData": network.RHEL6_NetworkData,
+ "PartData": partition.F12_PartData,
+ "RaidData": raid.F13_RaidData,
+ "RepoData": repo.RHEL6_RepoData,
+ "SshPwData": sshpw.F13_SshPwData,
+ "UserData": user.F12_UserData,
+ "VolGroupData": volgroup.FC3_VolGroupData,
+ "ZFCPData": zfcp.F12_ZFCPData,
+ }
+}
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2008 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.version import *
+
+class F10Handler(BaseHandler):
+ version = F10
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2008 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.version import *
+
+class F11Handler(BaseHandler):
+ version = F11
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2009 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.version import *
+
+class F12Handler(BaseHandler):
+ version = F12
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2009 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.version import *
+
+class F13Handler(BaseHandler):
+ version = F13
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2010 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.version import *
+
+class F14Handler(BaseHandler):
+ version = F14
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2010 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.version import *
+
+class F15Handler(BaseHandler):
+ version = F15
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2011 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.version import *
+
+class F16Handler(BaseHandler):
+ version = F16
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.version import *
+
+class F7Handler(BaseHandler):
+ version = F7
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.version import *
+
+class F8Handler(BaseHandler):
+ version = F8
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.version import *
+
+class F9Handler(BaseHandler):
+ version = F9
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.version import *
+
+class FC3Handler(BaseHandler):
+ version = FC3
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.version import *
+
+class FC4Handler(BaseHandler):
+ version = FC4
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.version import *
+
+class FC5Handler(BaseHandler):
+ version = FC5
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.version import *
+
+class FC6Handler(BaseHandler):
+ version = FC6
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.version import *
+
+class RHEL3Handler(BaseHandler):
+ version = RHEL3
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.version import *
+
+class RHEL4Handler(BaseHandler):
+ version = RHEL4
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.version import *
+
+class RHEL5Handler(BaseHandler):
+ version = RHEL5
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2010 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+from pykickstart.base import *
+from pykickstart.version import *
+
+class RHEL6Handler(BaseHandler):
+ version = RHEL6
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2009 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+"""
+Base classes for internal pykickstart use.
+
+The module exports the following important classes:
+
+ KickstartObject - The base class for all classes in pykickstart
+"""
+
+class KickstartObject(object):
+ """The base class for all other classes in pykickstart."""
+ def __init__(self, *args, **kwargs):
+ """Create a new KickstartObject instance. All other classes in
+ pykickstart should be derived from this one. Instance attributes:
+ """
+ pass
+
+ def __str__(self):
+ return ""
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+"""
+Specialized option handling.
+
+This module exports two classes:
+
+ KSOptionParser - A specialized subclass of OptionParser to be used
+ in BaseHandler subclasses.
+
+ KSOption - A specialized subclass of Option.
+"""
+import warnings
+from copy import copy
+from optparse import *
+
+from constants import *
+from errors import *
+from version import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+class KSOptionParser(OptionParser):
+ """A specialized subclass of optparse.OptionParser to handle extra option
+ attribute checking, work error reporting into the KickstartParseError
+ framework, and to turn off the default help.
+ """
+ def exit(self, status=0, msg=None):
+ pass
+
+ def error(self, msg):
+ if self.lineno != None:
+ raise KickstartParseError ( formatErrorMsg(self.lineno, msg=msg))
+ else:
+ raise KickstartParseError ( msg)
+
+ def keys(self):
+ retval = []
+
+ for opt in self.option_list:
+ if opt not in retval:
+ retval.append(opt.dest)
+
+ return retval
+
+ def _init_parsing_state (self):
+ OptionParser._init_parsing_state(self)
+ self.option_seen = {}
+
+ def check_values (self, values, args):
+ def seen(self, option):
+ return self.option_seen.has_key(option)
+
+ def usedTooNew(self, option):
+ return option.introduced and option.introduced > self.version
+
+ def usedDeprecated(self, option):
+ return option.deprecated
+
+ def usedRemoved(self, option):
+ return option.removed and option.removed <= self.version
+
+ for option in filter(lambda o: isinstance(o, Option), self.option_list):
+ if option.required and not seen(self, option):
+ raise KickstartValueError (formatErrorMsg(self.lineno, _("Option %s is required") % option))
+ elif seen(self, option) and usedTooNew(self, option):
+ mapping = {"option": option, "intro": versionToString(option.introduced),
+ "version": versionToString(self.version)}
+ self.error(_("The %(option)s option was introduced in version %(intro)s, but you are using kickstart syntax version %(version)s.") % mapping)
+ elif seen(self, option) and usedRemoved(self, option):
+ mapping = {"option": option, "removed": versionToString(option.removed),
+ "version": versionToString(self.version)}
+
+ if option.removed == self.version:
+ self.error(_("The %(option)s option is no longer supported.") % mapping)
+ else:
+ self.error(_("The %(option)s option was removed in version %(removed)s, but you are using kickstart syntax version %(version)s.") % mapping)
+ elif seen(self, option) and usedDeprecated(self, option):
+ mapping = {"lineno": self.lineno, "option": option}
+ warnings.warn(_("Ignoring deprecated option on line %(lineno)s: The %(option)s option has been deprecated and no longer has any effect. It may be removed from future releases, which will result in a fatal error from kickstart. Please modify your kickstart file to remove this option.") % mapping, DeprecationWarning)
+
+ return (values, args)
+
+ def parse_args(self, *args, **kwargs):
+ if kwargs.has_key("lineno"):
+ self.lineno = kwargs.pop("lineno")
+
+ return OptionParser.parse_args(self, **kwargs)
+
+ def __init__(self, mapping=None, version=None):
+ """Create a new KSOptionParser instance. Each KickstartCommand
+ subclass should create one instance of KSOptionParser, providing
+ at least the lineno attribute. mapping and version are not required.
+ Instance attributes:
+
+ mapping -- A mapping from option strings to different values.
+ version -- The version of the kickstart syntax we are checking
+ against.
+ """
+ OptionParser.__init__(self, option_class=KSOption,
+ add_help_option=False,
+ conflict_handler="resolve")
+ if mapping is None:
+ self.map = {}
+ else:
+ self.map = mapping
+
+ self.lineno = None
+ self.option_seen = {}
+ self.version = version
+
+def _check_ksboolean(option, opt, value):
+ if value.lower() in ("on", "yes", "true", "1"):
+ return True
+ elif value.lower() in ("off", "no", "false", "0"):
+ return False
+ else:
+ mapping = {"opt": opt, "value": 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
+
+# Creates a new Option class that supports several new attributes:
+# - required: any option with this attribute must be supplied or an exception
+# is thrown
+# - introduced: the kickstart syntax version that this option first appeared
+# in - an exception will be raised if the option is used and
+# the specified syntax version is less than the value of this
+# attribute
+# - deprecated: the kickstart syntax version that this option was deprecated
+# in - a DeprecationWarning will be thrown if the option is
+# used and the specified syntax version is greater than the
+# value of this attribute
+# - removed: the kickstart syntax version that this option was removed in - an
+# exception will be raised if the option is used and the specified
+# syntax version is greated than the value of this attribute
+# Also creates a new type:
+# - ksboolean: support various kinds of boolean values on an option
+# And two new actions:
+# - map : allows you to define an opt -> val mapping such that dest gets val
+# when opt is seen
+# - map_extend: allows you to define an opt -> [val1, ... valn] mapping such
+# that dest gets a list of vals built up when opt is seen
+class KSOption (Option):
+ ATTRS = Option.ATTRS + ['introduced', 'deprecated', 'removed', 'required']
+ ACTIONS = Option.ACTIONS + ("map", "map_extend",)
+ STORE_ACTIONS = Option.STORE_ACTIONS + ("map", "map_extend",)
+
+ TYPES = Option.TYPES + ("ksboolean", "string")
+ TYPE_CHECKER = copy(Option.TYPE_CHECKER)
+ TYPE_CHECKER["ksboolean"] = _check_ksboolean
+ TYPE_CHECKER["string"] = _check_string
+
+ def _check_required(self):
+ if self.required and not self.takes_value():
+ raise OptionError(_("Required flag set for option that doesn't take a value"), self)
+
+ # Make sure _check_required() is called from the constructor!
+ CHECK_METHODS = Option.CHECK_METHODS + [_check_required]
+
+ def process (self, opt, value, values, parser):
+ Option.process(self, opt, value, values, parser)
+ parser.option_seen[self] = 1
+
+ # Override default take_action method to handle our custom actions.
+ def take_action(self, action, dest, opt, value, values, parser):
+ if action == "map":
+ values.ensure_value(dest, parser.map[opt.lstrip('-')])
+ elif action == "map_extend":
+ values.ensure_value(dest, []).extend(parser.map[opt.lstrip('-')])
+ else:
+ Option.take_action(self, action, dest, opt, value, values, parser)
+
+ def takes_value(self):
+ # Deprecated options don't take a value.
+ return Option.takes_value(self) and not self.deprecated
+
+ def __init__(self, *args, **kwargs):
+ self.deprecated = False
+ self.required = False
+ Option.__init__(self, *args, **kwargs)
--- /dev/null
+#
+# parser.py: Kickstart file parser.
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2005, 2006, 2007, 2008, 2011 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+"""
+Main kickstart file processing module.
+
+This module exports several important classes:
+
+ Script - Representation of a single %pre, %post, or %traceback script.
+
+ Packages - Representation of the %packages section.
+
+ KickstartParser - The kickstart file parser state machine.
+"""
+from collections import Iterator
+import os
+import shlex
+import sys
+import tempfile
+from copy import copy
+from optparse import *
+from urlgrabber import urlread
+import urlgrabber.grabber as grabber
+
+import constants
+from errors import KickstartError, KickstartParseError, KickstartValueError, formatErrorMsg
+from ko import KickstartObject
+from sections import *
+import version
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+STATE_END = "end"
+STATE_COMMANDS = "commands"
+
+ver = version.DEVEL
+
+def _preprocessStateMachine (lineIter):
+ l = None
+ lineno = 0
+
+ # Now open an output kickstart file that we are going to write to one
+ # line at a time.
+ (outF, outName) = tempfile.mkstemp("-ks.cfg", "", "/tmp")
+
+ while True:
+ try:
+ l = lineIter.next()
+ except StopIteration:
+ break
+
+ # At the end of the file?
+ if l == "":
+ break
+
+ lineno += 1
+ url = None
+
+ ll = l.strip()
+ if not ll.startswith("%ksappend"):
+ os.write(outF, l)
+ continue
+
+ # Try to pull down the remote file.
+ try:
+ ksurl = ll.split(' ')[1]
+ except:
+ raise KickstartParseError (formatErrorMsg(lineno, msg=_("Illegal url for %%ksappend: %s") % ll))
+
+ try:
+ url = grabber.urlopen(ksurl)
+ except grabber.URLGrabError as e:
+ raise KickstartError (formatErrorMsg(lineno, msg=_("Unable to open %%ksappend file: %s") % e.strerror))
+ else:
+ # Sanity check result. Sometimes FTP doesn't catch a file
+ # is missing.
+ try:
+ if url.size < 1:
+ raise KickstartError (formatErrorMsg(lineno, msg=_("Unable to open %%ksappend file")))
+ except:
+ raise KickstartError (formatErrorMsg(lineno, msg=_("Unable to open %%ksappend file")))
+
+ # If that worked, write the remote file to the output kickstart
+ # file in one burst. Then close everything up to get ready to
+ # read ahead in the input file. This allows multiple %ksappend
+ # lines to exist.
+ if url is not None:
+ os.write(outF, url.read())
+ url.close()
+
+ # All done - close the temp file and return its location.
+ os.close(outF)
+ return outName
+
+def preprocessFromString (s):
+ """Preprocess the kickstart file, provided as the string str. This
+ method is currently only useful for handling %ksappend lines,
+ which need to be fetched before the real kickstart parser can be
+ run. Returns the location of the complete kickstart file.
+ """
+ i = iter(s.splitlines(True) + [""])
+ rc = _preprocessStateMachine (i.next)
+ return rc
+
+def preprocessKickstart (f):
+ """Preprocess the kickstart file, given by the filename file. This
+ method is currently only useful for handling %ksappend lines,
+ which need to be fetched before the real kickstart parser can be
+ run. Returns the location of the complete kickstart file.
+ """
+ try:
+ fh = urlopen(f)
+ except grabber.URLGrabError as e:
+ raise KickstartError (formatErrorMsg(0, msg=_("Unable to open input kickstart file: %s") % e.strerror))
+
+ rc = _preprocessStateMachine (iter(fh.readlines()))
+ fh.close()
+ return rc
+
+class PutBackIterator(Iterator):
+ def __init__(self, iterable):
+ self._iterable = iter(iterable)
+ self._buf = None
+
+ def __iter__(self):
+ return self
+
+ def put(self, s):
+ self._buf = s
+
+ def next(self):
+ if self._buf:
+ retval = self._buf
+ self._buf = None
+ return retval
+ else:
+ return self._iterable.next()
+
+###
+### SCRIPT HANDLING
+###
+class Script(KickstartObject):
+ """A class representing a single kickstart script. If functionality beyond
+ just a data representation is needed (for example, a run method in
+ anaconda), Script may be subclassed. Although a run method is not
+ provided, most of the attributes of Script have to do with running the
+ script. Instances of Script are held in a list by the Version object.
+ """
+ def __init__(self, script, *args , **kwargs):
+ """Create a new Script instance. Instance attributes:
+
+ errorOnFail -- If execution of the script fails, should anaconda
+ stop, display an error, and then reboot without
+ running any other scripts?
+ inChroot -- Does the script execute in anaconda's chroot
+ environment or not?
+ interp -- The program that should be used to interpret this
+ script.
+ lineno -- The line number this script starts on.
+ logfile -- Where all messages from the script should be logged.
+ script -- A string containing all the lines of the script.
+ type -- The type of the script, which can be KS_SCRIPT_* from
+ pykickstart.constants.
+ """
+ KickstartObject.__init__(self, *args, **kwargs)
+ self.script = "".join(script)
+
+ self.interp = kwargs.get("interp", "/bin/sh")
+ self.inChroot = kwargs.get("inChroot", False)
+ self.lineno = kwargs.get("lineno", None)
+ self.logfile = kwargs.get("logfile", None)
+ self.errorOnFail = kwargs.get("errorOnFail", False)
+ self.type = kwargs.get("type", constants.KS_SCRIPT_PRE)
+
+ def __str__(self):
+ """Return a string formatted for output to a kickstart file."""
+ retval = ""
+
+ if self.type == constants.KS_SCRIPT_PRE:
+ retval += '\n%pre'
+ elif self.type == constants.KS_SCRIPT_POST:
+ 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
+ if self.type == constants.KS_SCRIPT_POST and not self.inChroot:
+ retval += " --nochroot"
+ if self.logfile != None:
+ retval += " --logfile %s" % self.logfile
+ if self.errorOnFail:
+ retval += " --erroronfail"
+
+ if self.script.endswith("\n"):
+ if ver >= version.F8:
+ return retval + "\n%s%%end\n" % self.script
+ else:
+ return retval + "\n%s\n" % self.script
+ else:
+ if ver >= version.F8:
+ return retval + "\n%s\n%%end\n" % self.script
+ else:
+ return retval + "\n%s\n" % self.script
+
+
+##
+## PACKAGE HANDLING
+##
+class Group:
+ """A class representing a single group in the %packages section."""
+ def __init__(self, name="", include=constants.GROUP_DEFAULT):
+ """Create a new Group instance. Instance attributes:
+
+ name -- The group's identifier
+ include -- The level of how much of the group should be included.
+ Values can be GROUP_* from pykickstart.constants.
+ """
+ self.name = name
+ self.include = include
+
+ def __str__(self):
+ """Return a string formatted for output to a kickstart file."""
+ if self.include == constants.GROUP_REQUIRED:
+ return "@%s --nodefaults" % self.name
+ elif self.include == constants.GROUP_ALL:
+ return "@%s --optional" % self.name
+ else:
+ return "@%s" % self.name
+
+ def __cmp__(self, other):
+ if self.name < other.name:
+ return -1
+ elif self.name > other.name:
+ return 1
+ return 0
+
+class Packages(KickstartObject):
+ """A class representing the %packages section of the kickstart file."""
+ def __init__(self, *args, **kwargs):
+ """Create a new Packages instance. Instance attributes:
+
+ addBase -- Should the Base group be installed even if it is
+ not specified?
+ default -- Should the default package set be selected?
+ excludedList -- A list of all the packages marked for exclusion in
+ the %packages section, without the leading minus
+ symbol.
+ excludeDocs -- Should documentation in each package be excluded?
+ groupList -- A list of Group objects representing all the groups
+ specified in the %packages section. Names will be
+ stripped of the leading @ symbol.
+ excludedGroupList -- A list of Group objects representing all the
+ groups specified for removal in the %packages
+ section. Names will be stripped of the leading
+ -@ symbols.
+ handleMissing -- If unknown packages are specified in the %packages
+ section, should it be ignored or not? Values can
+ be KS_MISSING_* from pykickstart.constants.
+ packageList -- A list of all the packages specified in the
+ %packages section.
+ instLangs -- A list of languages to install.
+ """
+ KickstartObject.__init__(self, *args, **kwargs)
+
+ self.addBase = True
+ self.default = False
+ self.excludedList = []
+ self.excludedGroupList = []
+ self.excludeDocs = False
+ self.groupList = []
+ self.handleMissing = constants.KS_MISSING_PROMPT
+ self.packageList = []
+ self.tpk_packageList = []
+ self.instLangs = None
+
+ def __str__(self):
+ """Return a string formatted for output to a kickstart file."""
+ pkgs = ""
+
+ if not self.default:
+ grps = self.groupList
+ grps.sort()
+ for grp in grps:
+ pkgs += "%s\n" % grp.__str__()
+
+ p = self.packageList
+ p.sort()
+ for pkg in p:
+ pkgs += "%s\n" % pkg
+
+ grps = self.excludedGroupList
+ grps.sort()
+ for grp in grps:
+ pkgs += "-%s\n" % grp.__str__()
+
+ p = self.excludedList
+ p.sort()
+ for pkg in p:
+ pkgs += "-%s\n" % pkg
+
+ if pkgs == "":
+ return ""
+
+ retval = "\n%packages"
+
+ if self.default:
+ retval += " --default"
+ if self.excludeDocs:
+ retval += " --excludedocs"
+ if not self.addBase:
+ retval += " --nobase"
+ if self.handleMissing == constants.KS_MISSING_IGNORE:
+ retval += " --ignoremissing"
+ if self.instLangs:
+ retval += " --instLangs=%s" % self.instLangs
+
+ if ver >= version.F8:
+ return retval + "\n" + pkgs + "\n%end\n"
+ else:
+ return retval + "\n" + pkgs + "\n"
+
+ def _processGroup (self, line):
+ op = OptionParser()
+ op.add_option("--nodefaults", action="store_true", default=False)
+ op.add_option("--optional", action="store_true", default=False)
+
+ (opts, extra) = op.parse_args(args=line.split())
+
+ if opts.nodefaults and opts.optional:
+ raise KickstartValueError (_("Group cannot specify both --nodefaults and --optional"))
+
+ # If the group name has spaces in it, we have to put it back together
+ # now.
+ grp = " ".join(extra)
+
+ if opts.nodefaults:
+ self.groupList.append(Group(name=grp, include=constants.GROUP_REQUIRED))
+ elif opts.optional:
+ self.groupList.append(Group(name=grp, include=constants.GROUP_ALL))
+ else:
+ self.groupList.append(Group(name=grp, include=constants.GROUP_DEFAULT))
+
+ def add (self, pkgList):
+ """Given a list of lines from the input file, strip off any leading
+ symbols and add the result to the appropriate list.
+ """
+ existingExcludedSet = set(self.excludedList)
+ existingPackageSet = set(self.packageList)
+ newExcludedSet = set()
+ newPackageSet = set()
+
+ excludedGroupList = []
+
+ for pkg in pkgList:
+ stripped = pkg.strip()
+
+ if stripped[0] == "@":
+ self._processGroup(stripped[1:])
+ elif stripped[0] == "-":
+ if stripped[1] == "@":
+ excludedGroupList.append(Group(name=stripped[2:]))
+ else:
+ newExcludedSet.add(stripped[1:])
+ else:
+ newPackageSet.add(stripped)
+
+ # Groups have to be excluded in two different ways (note: can't use
+ # sets here because we have to store objects):
+ excludedGroupNames = map(lambda g: g.name, excludedGroupList)
+
+ # First, an excluded group may be cancelling out a previously given
+ # one. This is often the case when using %include. So there we should
+ # just remove the group from the list.
+ self.groupList = filter(lambda g: g.name not in excludedGroupNames, self.groupList)
+
+ # Second, the package list could have included globs which are not
+ # processed by pykickstart. In that case we need to preserve a list of
+ # excluded groups so whatever tool doing package/group installation can
+ # take appropriate action.
+ self.excludedGroupList.extend(excludedGroupList)
+
+ existingPackageSet = (existingPackageSet - newExcludedSet) | newPackageSet
+ existingExcludedSet = (existingExcludedSet - existingPackageSet) | newExcludedSet
+
+ 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
+###
+class KickstartParser:
+ """The kickstart file parser class as represented by a basic state
+ machine. To create a specialized parser, make a subclass and override
+ any of the methods you care about. Methods that don't need to do
+ anything may just pass. However, _stateMachine should never be
+ overridden.
+ """
+ def __init__ (self, handler, followIncludes=True, errorsAreFatal=True,
+ missingIncludeIsFatal=True):
+ """Create a new KickstartParser instance. Instance attributes:
+
+ errorsAreFatal -- Should errors cause processing to halt, or
+ just print a message to the screen? This
+ is most useful for writing syntax checkers
+ that may want to continue after an error is
+ encountered.
+ followIncludes -- If %include is seen, should the included
+ file be checked as well or skipped?
+ handler -- An instance of a BaseHandler subclass. If
+ None, the input file will still be parsed
+ but no data will be saved and no commands
+ will be executed.
+ missingIncludeIsFatal -- Should missing include files be fatal, even
+ if errorsAreFatal is False?
+ """
+ self.errorsAreFatal = errorsAreFatal
+ self.followIncludes = followIncludes
+ self.handler = handler
+ self.currentdir = {}
+ self.missingIncludeIsFatal = missingIncludeIsFatal
+
+ self._state = STATE_COMMANDS
+ self._includeDepth = 0
+ self._line = ""
+
+ self.version = self.handler.version
+
+ global ver
+ ver = self.version
+
+ self._sections = {}
+ self.setupSections()
+
+ def _reset(self):
+ """Reset the internal variables of the state machine for a new kickstart file."""
+ self._state = STATE_COMMANDS
+ self._includeDepth = 0
+
+ def getSection(self, s):
+ """Return a reference to the requested section (s must start with '%'s),
+ or raise KeyError if not found.
+ """
+ return self._sections[s]
+
+ def handleCommand (self, lineno, args):
+ """Given the list of command and arguments, call the Version's
+ dispatcher method to handle the command. Returns the command or
+ data object returned by the dispatcher. This method may be
+ overridden in a subclass if necessary.
+ """
+ if self.handler:
+ self.handler.currentCmd = args[0]
+ self.handler.currentLine = self._line
+ retval = self.handler.dispatcher(args, lineno)
+
+ return retval
+
+ def registerSection(self, obj):
+ """Given an instance of a Section subclass, register the new section
+ with the parser. Calling this method means the parser will
+ recognize your new section and dispatch into the given object to
+ handle it.
+ """
+ if not obj.sectionOpen:
+ raise TypeError ("no sectionOpen given for section %s" % obj)
+
+ if not obj.sectionOpen.startswith("%"):
+ raise TypeError ("section %s tag does not start with a %%" % obj.sectionOpen)
+
+ self._sections[obj.sectionOpen] = obj
+
+ def _finalize(self, obj):
+ """Called at the close of a kickstart section to take any required
+ actions. Internally, this is used to add scripts once we have the
+ whole body read.
+ """
+ obj.finalize()
+ self._state = STATE_COMMANDS
+
+ def _handleSpecialComments(self, line):
+ """Kickstart recognizes a couple special comments."""
+ if self._state != STATE_COMMANDS:
+ return
+
+ # Save the platform for s-c-kickstart.
+ if line[:10] == "#platform=":
+ self.handler.platform = self._line[11:]
+
+ def _readSection(self, lineIter, lineno):
+ obj = self._sections[self._state]
+
+ while True:
+ try:
+ line = lineIter.next()
+ if line == "":
+ # This section ends at the end of the file.
+ if self.version >= version.F8:
+ raise KickstartParseError (formatErrorMsg(lineno, msg=_("Section does not end with %%end.")))
+
+ self._finalize(obj)
+ except StopIteration:
+ break
+
+ lineno += 1
+
+ # Throw away blank lines and comments, unless the section wants all
+ # lines.
+ if self._isBlankOrComment(line) and not obj.allLines:
+ continue
+
+ if line.startswith("%"):
+ args = shlex.split(line)
+
+ if args and args[0] == "%end":
+ # This is a properly terminated section.
+ self._finalize(obj)
+ break
+ elif args and args[0] == "%ksappend":
+ continue
+ elif args and (self._validState(args[0]) or args[0] in ["%include", "%ksappend"]):
+ # This is an unterminated section.
+ if self.version >= version.F8:
+ raise KickstartParseError (formatErrorMsg(lineno, msg=_("Section does not end with %%end.")))
+
+ # Finish up. We do not process the header here because
+ # kicking back out to STATE_COMMANDS will ensure that happens.
+ lineIter.put(line)
+ lineno -= 1
+ self._finalize(obj)
+ break
+ else:
+ # This is just a line within a section. Pass it off to whatever
+ # section handles it.
+ obj.handleLine(line)
+
+ return lineno
+
+ def _validState(self, st):
+ """Is the given section tag one that has been registered with the parser?"""
+ return st in self._sections.keys()
+
+ def _tryFunc(self, fn):
+ """Call the provided function (which doesn't take any arguments) and
+ do the appropriate error handling. If errorsAreFatal is False, this
+ function will just print the exception and keep going.
+ """
+ try:
+ fn()
+ except Exception as msg:
+ if self.errorsAreFatal:
+ raise
+ else:
+ print (msg)
+
+ def _isBlankOrComment(self, line):
+ return line.isspace() or line == "" or line.lstrip()[0] == '#'
+
+ def _stateMachine(self, lineIter):
+ # For error reporting.
+ lineno = 0
+
+ while True:
+ # Get the next line out of the file, quitting if this is the last line.
+ try:
+ self._line = lineIter.next()
+ if self._line == "":
+ break
+ except StopIteration:
+ break
+
+ lineno += 1
+
+ # Eliminate blank lines, whitespace-only lines, and comments.
+ if self._isBlankOrComment(self._line):
+ self._handleSpecialComments(self._line)
+ continue
+
+ # Remove any end-of-line comments.
+ sanitized = self._line.split("#")[0]
+
+ # Then split the line.
+ args = shlex.split(sanitized.rstrip())
+
+ if args[0] == "%include":
+ # This case comes up primarily in ksvalidator.
+ if not self.followIncludes:
+ continue
+
+ if len(args) == 1 or not args[1]:
+ raise KickstartParseError (formatErrorMsg(lineno))
+
+ self._includeDepth += 1
+
+ try:
+ self.readKickstart(args[1], reset=False)
+ except KickstartError:
+ # Handle the include file being provided over the
+ # network in a %pre script. This case comes up in the
+ # early parsing in anaconda.
+ if self.missingIncludeIsFatal:
+ raise
+
+ self._includeDepth -= 1
+ continue
+
+ # Now on to the main event.
+ if self._state == STATE_COMMANDS:
+ if args[0] == "%ksappend":
+ # This is handled by the preprocess* functions, so continue.
+ continue
+ elif args[0][0] == '%':
+ # This is the beginning of a new section. Handle its header
+ # here.
+ newSection = args[0]
+ if not self._validState(newSection):
+ raise KickstartParseError (formatErrorMsg(lineno, msg=_("Unknown kickstart section: %s" % newSection)))
+
+ self._state = newSection
+ obj = self._sections[self._state]
+ self._tryFunc(lambda: obj.handleHeader(lineno, args))
+
+ # This will handle all section processing, kicking us back
+ # out to STATE_COMMANDS at the end with the current line
+ # being the next section header, etc.
+ lineno = self._readSection(lineIter, lineno)
+ else:
+ # This is a command in the command section. Dispatch to it.
+ self._tryFunc(lambda: self.handleCommand(lineno, args))
+ elif self._state == STATE_END:
+ break
+
+ def readKickstartFromString (self, s, reset=True):
+ """Process a kickstart file, provided as the string str."""
+ if reset:
+ self._reset()
+
+ # Add a "" to the end of the list so the string reader acts like the
+ # file reader and we only get StopIteration when we're after the final
+ # line of input.
+ i = PutBackIterator(s.splitlines(True) + [""])
+ self._stateMachine (i)
+
+ def readKickstart(self, f, reset=True):
+ """Process a kickstart file, given by the filename f."""
+ if reset:
+ self._reset()
+
+ # an %include might not specify a full path. if we don't try to figure
+ # out what the path should have been, then we're unable to find it
+ # requiring full path specification, though, sucks. so let's make
+ # the reading "smart" by keeping track of what the path is at each
+ # include depth.
+ if not os.path.exists(f):
+ if self.currentdir.has_key(self._includeDepth - 1):
+ if os.path.exists(os.path.join(self.currentdir[self._includeDepth - 1], f)):
+ f = os.path.join(self.currentdir[self._includeDepth - 1], f)
+
+ cd = os.path.dirname(f)
+ if not cd.startswith("/"):
+ cd = os.path.abspath(cd)
+ self.currentdir[self._includeDepth] = cd
+
+ try:
+ s = urlread(f)
+ except grabber.URLGrabError as e:
+ raise KickstartError (formatErrorMsg(0, msg=_("Unable to open input kickstart file: %s") % e.strerror))
+
+ self.readKickstartFromString(s, reset=False)
+
+ def setupSections(self):
+ """Install the sections all kickstart files support. You may override
+ this method in a subclass, but should avoid doing so unless you know
+ what you're doing.
+ """
+ self._sections = {}
+
+ # Install the sections all kickstart files support.
+ 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))
+
--- /dev/null
+#
+# sections.py: Kickstart file sections.
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2011 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+"""
+This module exports the classes that define a section of a kickstart file. A
+section is a chunk of the file starting with a %tag and ending with a %end.
+Examples of sections include %packages, %pre, and %post.
+
+You may use this module to define your own custom sections which will be
+treated just the same as a predefined one by the kickstart parser. All that
+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 *
+
+class Section(object):
+ """The base class for defining kickstart sections. You are free to
+ subclass this as appropriate.
+
+ Class attributes:
+
+ allLines -- Does this section require the parser to call handleLine
+ for every line in the section, even blanks and comments?
+ sectionOpen -- The string that denotes the start of this section. You
+ must start your tag with a percent sign.
+ timesSeen -- This attribute is for informational purposes only. It is
+ incremented every time handleHeader is called to keep
+ track of the number of times a section of this type is
+ seen.
+ """
+ allLines = False
+ sectionOpen = ""
+ timesSeen = 0
+
+ def __init__(self, handler, **kwargs):
+ """Create a new Script instance. At the least, you must pass in an
+ instance of a baseHandler subclass.
+
+ Valid kwargs:
+
+ dataObj --
+ """
+ self.handler = handler
+
+ self.version = self.handler.version
+
+ self.dataObj = kwargs.get("dataObj", None)
+
+ def finalize(self):
+ """This method is called when the %end tag for a section is seen. It
+ is not required to be provided.
+ """
+ pass
+
+ def handleLine(self, line):
+ """This method is called for every line of a section. Take whatever
+ action is appropriate. While this method is not required to be
+ provided, not providing it does not make a whole lot of sense.
+
+ Arguments:
+
+ line -- The complete line, with any trailing newline.
+ """
+ pass
+
+ def handleHeader(self, lineno, args):
+ """This method is called when the opening tag for a section is seen.
+ Not all sections will need this method, though all provided with
+ kickstart include one.
+
+ Arguments:
+
+ args -- A list of all strings passed as arguments to the section
+ opening tag.
+ """
+ self.timesSeen += 1
+
+class NullSection(Section):
+ """This defines a section that pykickstart will recognize but do nothing
+ with. If the parser runs across a %section that has no object registered,
+ it will raise an error. Sometimes, you may want to simply ignore those
+ sections instead. This class is useful for that purpose.
+ """
+ def __init__(self, *args, **kwargs):
+ """Create a new NullSection instance. You must pass a sectionOpen
+ parameter (including a leading '%') for the section you wish to
+ ignore.
+ """
+ Section.__init__(self, *args, **kwargs)
+ self.sectionOpen = kwargs.get("sectionOpen")
+
+class ScriptSection(Section):
+ allLines = True
+
+ def __init__(self, *args, **kwargs):
+ Section.__init__(self, *args, **kwargs)
+ self._script = {}
+ self._resetScript()
+
+ def _getParser(self):
+ op = KSOptionParser(self.version)
+ op.add_option("--erroronfail", dest="errorOnFail", action="store_true",
+ default=False)
+ op.add_option("--interpreter", dest="interpreter", default="/bin/sh")
+ op.add_option("--log", "--logfile", dest="log")
+ return op
+
+ def _resetScript(self):
+ self._script = {"interp": "/bin/sh", "log": None, "errorOnFail": False,
+ "lineno": None, "chroot": False, "body": []}
+
+ def handleLine(self, line):
+ self._script["body"].append(line)
+
+ def finalize(self):
+ if " ".join(self._script["body"]).strip() == "":
+ return
+
+ kwargs = {"interp": self._script["interp"],
+ "inChroot": self._script["chroot"],
+ "lineno": self._script["lineno"],
+ "logfile": self._script["log"],
+ "errorOnFail": self._script["errorOnFail"],
+ "type": self._script["type"]}
+
+ s = self.dataObj (self._script["body"], **kwargs)
+ self._resetScript()
+
+ if self.handler:
+ self.handler.scripts.append(s)
+
+ def handleHeader(self, lineno, args):
+ """Process the arguments to a %pre/%post/%traceback header for later
+ setting on a Script instance once the end of the script is found.
+ This method may be overridden in a subclass if necessary.
+ """
+ Section.handleHeader(self, lineno, args)
+ op = self._getParser()
+
+ (opts, extra) = op.parse_args(args=args[1:], lineno=lineno)
+
+ self._script["interp"] = opts.interpreter
+ self._script["lineno"] = lineno
+ self._script["log"] = opts.log
+ self._script["errorOnFail"] = opts.errorOnFail
+ if hasattr(opts, "nochroot"):
+ self._script["chroot"] = not opts.nochroot
+
+class PreScriptSection(ScriptSection):
+ sectionOpen = "%pre"
+
+ def _resetScript(self):
+ ScriptSection._resetScript(self)
+ self._script["type"] = KS_SCRIPT_PRE
+
+class PostScriptSection(ScriptSection):
+ sectionOpen = "%post"
+
+ def _getParser(self):
+ op = ScriptSection._getParser(self)
+ op.add_option("--nochroot", dest="nochroot", action="store_true",
+ default=False)
+ return op
+
+ def _resetScript(self):
+ ScriptSection._resetScript(self)
+ self._script["chroot"] = True
+ self._script["type"] = KS_SCRIPT_POST
+
+class TracebackScriptSection(ScriptSection):
+ sectionOpen = "%traceback"
+
+ def _resetScript(self):
+ 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"
+
+ def handleLine(self, line):
+ if not self.handler:
+ return
+
+ (h, s, t) = line.partition('#')
+ line = h.rstrip()
+ self.handler.packages.add([line])
+
+ def handleHeader(self, lineno, args):
+ """Process the arguments to the %packages header and set attributes
+ on the Version's Packages instance appropriate. This method may be
+ overridden in a subclass if necessary.
+ """
+ Section.handleHeader(self, lineno, args)
+ op = KSOptionParser(version=self.version)
+ op.add_option("--excludedocs", dest="excludedocs", action="store_true",
+ default=False)
+ op.add_option("--ignoremissing", dest="ignoremissing",
+ action="store_true", default=False)
+ op.add_option("--nobase", dest="nobase", action="store_true",
+ default=False)
+ op.add_option("--ignoredeps", dest="resolveDeps", action="store_false",
+ deprecated=FC4, removed=F9)
+ op.add_option("--resolvedeps", dest="resolveDeps", action="store_true",
+ deprecated=FC4, removed=F9)
+ op.add_option("--default", dest="defaultPackages", action="store_true",
+ default=False, introduced=F7)
+ op.add_option("--instLangs", dest="instLangs", type="string",
+ default="", introduced=F9)
+
+ (opts, extra) = op.parse_args(args=args[1:], lineno=lineno)
+
+ self.handler.packages.excludeDocs = opts.excludedocs
+ self.handler.packages.addBase = not opts.nobase
+ if opts.ignoremissing:
+ self.handler.packages.handleMissing = KS_MISSING_IGNORE
+ else:
+ self.handler.packages.handleMissing = KS_MISSING_PROMPT
+
+ if opts.defaultPackages:
+ self.handler.packages.default = True
+
+ 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)
--- /dev/null
+#
+# Chris Lumens <clumens@redhat.com>
+#
+# Copyright 2006, 2007, 2008, 2009, 2010 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
+# trademarks that are incorporated in the source code or documentation are not
+# subject to the GNU General Public License and may only be used or replicated
+# with the express permission of Red Hat, Inc.
+#
+"""
+Methods for working with kickstart versions.
+
+This module defines several symbolic constants that specify kickstart syntax
+versions. Each version corresponds roughly to one release of Red Hat Linux,
+Red Hat Enterprise Linux, or Fedora Core as these are where most syntax
+changes take place.
+
+This module also exports several functions:
+
+ makeVersion - Given a version number, return an instance of the
+ matching handler class.
+
+ returnClassForVersion - Given a version number, return the matching
+ handler class. This does not return an
+ instance of that class, however.
+
+ stringToVersion - Convert a string representation of a version number
+ into the symbolic constant.
+
+ versionToString - Perform the reverse mapping.
+
+ versionFromFile - Read a kickstart file and determine the version of
+ syntax it uses. This requires the kickstart file to
+ have a version= comment in it.
+"""
+import imputil, re, sys
+from urlgrabber import urlopen
+
+import gettext
+_ = lambda x: gettext.ldgettext("pykickstart", x)
+
+from pykickstart.errors import KickstartVersionError
+
+# Symbolic names for internal version numbers.
+RHEL3 = 900
+FC3 = 1000
+RHEL4 = 1100
+FC4 = 2000
+FC5 = 3000
+FC6 = 4000
+RHEL5 = 4100
+F7 = 5000
+F8 = 6000
+F9 = 7000
+F10 = 8000
+F11 = 9000
+F12 = 10000
+F13 = 11000
+RHEL6 = 11100
+F14 = 12000
+F15 = 13000
+F16 = 14000
+
+# This always points at the latest version and is the default.
+DEVEL = F16
+
+# A one-to-one mapping from string representations to version numbers.
+versionMap = {
+ "DEVEL": DEVEL,
+ "FC3": FC3, "FC4": FC4, "FC5": FC5, "FC6": FC6, "F7": F7, "F8": F8,
+ "F9": F9, "F10": F10, "F11": F11, "F12": F12, "F13": F13,
+ "F14": F14, "F15": F15, "F16": F16,
+ "RHEL3": RHEL3, "RHEL4": RHEL4, "RHEL5": RHEL5, "RHEL6": RHEL6
+}
+
+def stringToVersion(s):
+ """Convert string into one of the provided version constants. Raises
+ KickstartVersionError if string does not match anything.
+ """
+ # First try these short forms.
+ try:
+ return versionMap[s.upper()]
+ except KeyError:
+ pass
+
+ # Now try the Fedora versions.
+ m = re.match("^fedora.* (\d+)$", s, re.I)
+
+ if m and m.group(1):
+ if versionMap.has_key("FC" + m.group(1)):
+ return versionMap["FC" + m.group(1)]
+ elif versionMap.has_key("F" + m.group(1)):
+ return versionMap["F" + m.group(1)]
+ else:
+ raise KickstartVersionError(_("Unsupported version specified: %s") % s)
+
+ # Now try the RHEL versions.
+ m = re.match("^red hat enterprise linux.* (\d+)([\.\d]*)$", s, re.I)
+
+ if m and m.group(1):
+ if versionMap.has_key("RHEL" + m.group(1)):
+ return versionMap["RHEL" + m.group(1)]
+ else:
+ raise KickstartVersionError(_("Unsupported version specified: %s") % s)
+
+ # If nothing else worked, we're out of options.
+ raise KickstartVersionError(_("Unsupported version specified: %s") % s)
+
+def versionToString(version, skipDevel=False):
+ """Convert version into a string representation of the version number.
+ This is the reverse operation of stringToVersion. Raises
+ KickstartVersionError if version does not match anything.
+ """
+ if not skipDevel and version == versionMap["DEVEL"]:
+ return "DEVEL"
+
+ for (key, val) in versionMap.iteritems():
+ if key == "DEVEL":
+ continue
+ elif val == version:
+ return key
+
+ raise KickstartVersionError(_("Unsupported version specified: %s") % version)
+
+def versionFromFile(f):
+ """Given a file or URL, look for a line starting with #version= and
+ return the version number. If no version is found, return DEVEL.
+ """
+ v = DEVEL
+
+ fh = urlopen(f)
+
+ while True:
+ try:
+ l = fh.readline()
+ except StopIteration:
+ break
+
+ # At the end of the file?
+ if l == "":
+ break
+
+ if l.isspace() or l.strip() == "":
+ continue
+
+ if l[:9] == "#version=":
+ v = stringToVersion(l[9:].rstrip())
+ break
+
+ fh.close()
+ return v
+
+def returnClassForVersion(version=DEVEL):
+ """Return the class of the syntax handler for version. version can be
+ either a string or the matching constant. Raises KickstartValueError
+ if version does not match anything.
+ """
+ try:
+ version = int(version)
+ module = "%s" % versionToString(version, skipDevel=True)
+ except ValueError:
+ module = "%s" % version
+ version = stringToVersion(version)
+
+ module = module.lower()
+
+ try:
+ import pykickstart.handlers
+ sys.path.extend(pykickstart.handlers.__path__)
+ found = imputil.imp.find_module(module)
+ loaded = imputil.imp.load_module(module, found[0], found[1], found[2])
+
+ for (k, v) in loaded.__dict__.iteritems():
+ if k.lower().endswith("%shandler" % module):
+ return v
+ except:
+ raise KickstartVersionError(_("Unsupported version specified: %s") % version)
+
+def makeVersion(version=DEVEL):
+ """Return a new instance of the syntax handler for version. version can be
+ either a string or the matching constant. This function is useful for
+ standalone programs which just need to handle a specific version of
+ kickstart syntax (as provided by a command line argument, for example)
+ and need to instantiate the correct object.
+ """
+ cl = returnClassForVersion(version)
+ return cl()
--- /dev/null
+#
+# Copyright (c) 2013 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os, sys
+
+__version__ = "0.28.19"
+
+cur_path = os.path.dirname(__file__) or '.'
+sys.path.insert(0, cur_path + '/3rdparty')
--- /dev/null
+#
+# Copyright (c) 2013 Intel Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# Following messages should be disabled in pylint
+# * Used * or ** magic (W0142)
+# * Unused variable (W0612)
+# * Used builtin function (W0141)
+# * Invalid name for type (C0103)
+# * Popen has no '%s' member (E1101)
+# pylint: disable= W0612, C0103, E1101
+
+""" Compression and Archiving
+
+Utility functions for creating archive files (tarballs, zip files, etc)
+and compressing files (gzip, bzip2, lzop, etc)
+"""
+
+import os
+import shutil
+import tempfile
+import subprocess
+from mic import msger
+
+__all__ = [
+ "get_compress_formats",
+ "compress",
+ "decompress",
+ "get_archive_formats",
+ "get_archive_suffixes",
+ "make_archive",
+ "extract_archive",
+ "compressing",
+ "packing",
+ ]
+
+# TODO: refine Error class for archive/extract
+
+def which(binary, path=None):
+ """ Find 'binary' in the directories listed in 'path'
+
+ @binary: the executable file to find
+ @path: the suposed path to search for, use $PATH if None
+ @retval: the absolute path if found, otherwise None
+ """
+ if path is None:
+ path = os.environ["PATH"]
+ for apath in path.split(os.pathsep):
+ fpath = os.path.join(apath, binary)
+ if os.path.isfile(fpath) and os.access(fpath, os.X_OK):
+ return fpath
+ return None
+
+def _call_external(cmdln_or_args):
+ """ Wapper for subprocess calls.
+
+ @cmdln_or_args: command line to be joined before execution.
+ @retval: a tuple (returncode, outdata, errdata).
+ """
+ if isinstance(cmdln_or_args, list):
+ shell = False
+ else:
+ shell = True
+ msger.info("Running command: " + " ".join(cmdln_or_args))
+
+ proc = subprocess.Popen(cmdln_or_args, shell=shell,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ (outdata, errdata) = proc.communicate()
+
+ return (proc.returncode, outdata, errdata)
+
+def _do_gzip(input_name, compression=True):
+ """ Compress/decompress the file with 'gzip' utility.
+
+ @input_name: the file name to compress/decompress
+ @compress: True for compressing, False for decompressing
+ @retval: the path of the compressed/decompressed file
+ """
+ if which("pigz") is not None:
+ compressor = "pigz"
+ else:
+ compressor = "gzip"
+
+ if compression:
+ cmdln = [compressor, "-f", input_name]
+ else:
+ cmdln = [compressor, "-d", "-f", input_name]
+
+ _call_external(cmdln)
+
+ if compression:
+ output_name = input_name + ".gz"
+ else:
+ # suppose that file name is suffixed with ".gz"
+ output_name = os.path.splitext(input_name)[0]
+
+ return output_name
+
+def _do_bzip2(input_name, compression=True):
+ """ Compress/decompress the file with 'bzip2' utility.
+
+ @input_name: the file name to compress/decompress
+ @compress: True for compressing, False for decompressing
+ @retval: the path of the compressed/decompressed file
+ """
+ if which("pbzip2") is not None:
+ compressor = "pbzip2"
+ else:
+ compressor = "bzip2"
+
+ if compression:
+ cmdln = [compressor, "-f", input_name]
+ else:
+ cmdln = [compressor, "-d", "-f", input_name]
+
+ _call_external(cmdln)
+
+ if compression:
+ output_name = input_name + ".bz2"
+ else:
+ # suppose that file name is suffixed with ".bz2"
+ output_name = os.path.splitext(input_name)[0]
+
+ return output_name
+
+def _do_lzop(input_name, compression=True):
+ """ Compress/decompress the file with 'lzop' utility.
+
+ @input_name: the file name to compress/decompress
+ @compress: True for compressing, False for decompressing
+ @retval: the path of the compressed/decompressed file
+ """
+ compressor = "lzop"
+
+ if compression:
+ cmdln = [compressor, "-f", "-U", input_name]
+ else:
+ cmdln = [compressor, "-d", "-f", "-U", input_name]
+
+ _call_external(cmdln)
+
+ if compression:
+ output_name = input_name + ".lzo"
+ else:
+ # suppose that file name is suffixed with ".lzo"
+ output_name = os.path.splitext(input_name)[0]
+
+ return output_name
+
+_COMPRESS_SUFFIXES = {
+ ".lzo" : [".lzo"],
+ ".gz" : [".gz"],
+ ".bz2" : [".bz2", ".bz"],
+ ".tar.lzo" : [".tar.lzo", ".tzo"],
+ ".tar.gz" : [".tar.gz", ".tgz", ".taz"],
+ ".tar.bz2" : [".tar.bz2", ".tbz", ".tbz2", ".tar.bz"],
+}
+
+_COMPRESS_FORMATS = {
+ "gz" : _do_gzip,
+ "bz2": _do_bzip2,
+ "lzo": _do_lzop,
+}
+
+def get_compress_formats():
+ """ Get the list of the supported compression formats
+
+ @retval: a list contained supported compress formats
+ """
+ return _COMPRESS_FORMATS.keys()
+
+def get_compress_suffixes():
+ """ Get the list of the support suffixes
+
+ @retval: a list contained all suffixes
+ """
+ suffixes = []
+ for key in _COMPRESS_SUFFIXES.keys():
+ suffix = _COMPRESS_SUFFIXES[key]
+ if (suffix):
+ suffixes.extend(suffix)
+
+ return suffixes
+
+def compress(file_path, compress_format):
+ """ Compress a given file
+
+ @file_path: the path of the file to compress
+ @compress_format: the compression format
+ @retval: the path of the compressed file
+ """
+ if not os.path.isfile(file_path):
+ raise OSError ("can't compress a file not existed: '%s'" % file_path)
+
+ try:
+ func = _COMPRESS_FORMATS[compress_format]
+ except KeyError:
+ raise ValueError ("unknown compress format '%s'" % compress_format)
+ return func(file_path, True)
+
+def decompress(file_path, decompress_format=None):
+ """ Decompess a give file
+
+ @file_path: the path of the file to decompress
+ @decompress_format: the format for decompression, None for auto detection
+ @retval: the path of the decompressed file
+ """
+ if not os.path.isfile(file_path):
+ raise OSError ("can't decompress a file not existed: '%s'" % file_path)
+
+ (file_name, file_ext) = os.path.splitext(file_path)
+ for key, suffixes in _COMPRESS_SUFFIXES.iteritems():
+ if file_ext in suffixes:
+ file_ext = key
+ break
+
+ if file_path != (file_name + file_ext):
+ shutil.move(file_path, file_name + file_ext)
+ file_path = file_name + file_ext
+
+ if not decompress_format:
+ decompress_format = os.path.splitext(file_path)[1].lstrip(".")
+
+ try:
+ func = _COMPRESS_FORMATS[decompress_format]
+ except KeyError:
+ raise ValueError ("unknown decompress format '%s'" % decompress_format)
+ return func(file_path, False)
+
+
+def _do_tar(archive_name, target_name):
+ """ Archive the directory or the file with 'tar' utility
+
+ @archive_name: the name of the tarball file
+ @target_name: the name of the target to tar
+ @retval: the path of the archived file
+ """
+ file_list = []
+ if os.path.isdir(target_name):
+ target_dir = target_name
+ target_name = "."
+ for target_file in os.listdir(target_dir):
+ file_list.append(target_file)
+ else:
+ target_dir = os.path.dirname(target_name)
+ target_name = os.path.basename(target_name)
+ file_list.append(target_name)
+ cmdln = ["tar", "-C", target_dir, "-cf", archive_name]
+ cmdln.extend(file_list)
+ _call_external(cmdln)
+
+ return archive_name
+
+def _do_untar(archive_name, target_dir=None):
+ """ Unarchive the archived file with 'tar' utility
+
+ @archive_name: the name of the archived file
+ @target_dir: the directory which the target locates
+ raise exception if fail to extract archive
+ """
+ if not target_dir:
+ target_dir = os.getcwd()
+ cmdln = ["tar", "-C", target_dir, "-xf", archive_name]
+ (returncode, stdout, stderr) = _call_external(cmdln)
+ if returncode != 0:
+ raise OSError (os.linesep.join([stdout, stderr]))
+
+def _imp_tarfile(archive_name, target_name):
+ """ Archive the directory or the file with tarfile module
+
+ @archive_name: the name of the tarball file
+ @target_name: the name of the target to tar
+ @retval: the path of the archived file
+ """
+ import tarfile
+
+ msger.info("Taring files to %s using tarfile module" % archive_name)
+ tar = tarfile.open(archive_name, 'w')
+ if os.path.isdir(target_name):
+ for child in os.listdir(target_name):
+ tar.add(os.path.join(target_name, child), child)
+ else:
+ tar.add(target_name, os.path.basename(target_name))
+
+ tar.close()
+ return archive_name
+
+def _make_tarball(archive_name, target_name, compressor=None):
+ """ Create a tarball from all the files under 'target_name' or itself.
+
+ @archive_name: the name of the archived file to create
+ @target_name: the directory or the file name to archive
+ @compressor: callback function to compress the tarball
+ @retval: indicate the compressing result
+ """
+ archive_dir = os.path.dirname(archive_name)
+ tarball_name = tempfile.mktemp(suffix=".tar", dir=archive_dir)
+
+ if which("tar") is not None:
+ _do_tar(tarball_name, target_name)
+ else:
+ _imp_tarfile(tarball_name, target_name)
+
+ if compressor:
+ tarball_name = compressor(tarball_name, True)
+
+ shutil.move(tarball_name, archive_name)
+
+ return os.path.exists(archive_name)
+
+def _extract_tarball(archive_name, target_dir, compressor=None):
+ """ Extract a tarball to a target directory
+
+ @archive_name: the name of the archived file to extract
+ @target_dir: the directory of the extracted target
+ """
+
+ _do_untar(archive_name, target_dir)
+
+def _make_zipfile(archive_name, target_name):
+ """ Create a zip file from all the files under 'target_name' or itself.
+
+ @archive_name: the name of the archived file
+ @target_name: the directory or the file name to archive
+ @retval: indicate the archiving result
+ """
+ import zipfile
+
+ msger.info("Zipping files to %s using zipfile module" % archive_name)
+ arv = zipfile.ZipFile(archive_name, 'w', compression=zipfile.ZIP_DEFLATED)
+
+ if os.path.isdir(target_name):
+ for dirpath, dirname, filenames in os.walk(target_name):
+ for filename in filenames:
+ filepath = os.path.normpath(os.path.join(dirpath, filename))
+ arcname = os.path.relpath(filepath, target_name)
+ if os.path.isfile(filepath):
+ arv.write(filepath, arcname)
+ else:
+ arv.write(target_name, os.path.basename(target_name))
+
+ arv.close()
+
+ return os.path.exists(archive_name)
+
+_ARCHIVE_SUFFIXES = {
+ "zip" : [".zip"],
+ "tar" : [".tar"],
+ "lzotar": [".tzo", ".tar.lzo"],
+ "gztar" : [".tgz", ".taz", ".tar.gz"],
+ "bztar" : [".tbz", ".tbz2", ".tar.bz", ".tar.bz2"],
+}
+
+_ARCHIVE_FORMATS = {
+ "zip" : ( _make_zipfile, {} ),
+ "tar" : ( _make_tarball, {"compressor" : None} ),
+ "lzotar": ( _make_tarball, {"compressor" : _do_lzop} ),
+ "gztar" : ( _make_tarball, {"compressor" : _do_gzip} ),
+ "bztar" : ( _make_tarball, {"compressor" : _do_bzip2} ),
+}
+
+def get_archive_formats():
+ """ Get the list of the supported formats for archiving
+
+ @retval: a list contained archive formats
+ """
+ return _ARCHIVE_FORMATS.keys()
+
+def get_archive_suffixes():
+ """ Get the list of the support suffixes
+
+ @retval: a list contained all suffixes
+ """
+ suffixes = []
+ for name in _ARCHIVE_FORMATS.keys():
+ suffix = _ARCHIVE_SUFFIXES.get(name, None)
+ if (suffix):
+ suffixes.extend(suffix)
+
+ return suffixes
+
+def make_archive(archive_name, target_name):
+ """ Create an archive file (eg. tar or zip).
+
+ @archive_name: the name of the archived file
+ @target_name: the directory or the file to archive
+ @retval: the archiving result
+ """
+ if not os.path.exists(target_name):
+ raise OSError ("archive object does not exist: '%s'" % target_name)
+
+ for aformat, suffixes in _ARCHIVE_SUFFIXES.iteritems():
+ if filter(archive_name.endswith, suffixes):
+ archive_format = aformat
+ break
+ else:
+ raise ValueError ("unknown archive suffix '%s'" % archive_name)
+
+ try:
+ func, kwargs = _ARCHIVE_FORMATS[archive_format]
+ except KeyError:
+ raise ValueError ("unknown archive format '%s'" % archive_format)
+
+ archive_name = os.path.abspath(archive_name)
+ target_name = os.path.abspath(target_name)
+
+ archive_dir = os.path.dirname(archive_name)
+ if not os.path.exists(archive_dir):
+ os.makedirs(archive_dir)
+
+ return func(archive_name, target_name, **kwargs)
+
+def extract_archive(archive_name, target_name):
+ """ Extract the given file
+
+ @archive_name: the name of the archived file to extract
+ @target_name: the directory name where the target locates
+ raise exception if fail to extract archive
+ """
+ if not os.path.exists(archive_name):
+ raise OSError ("archived object does not exist: '%s'" % archive_name)
+
+ archive_name = os.path.abspath(archive_name)
+ target_name = os.path.abspath(target_name)
+
+ if os.path.exists(target_name) and not os.path.isdir(target_name):
+ raise OSError ("%s should be directory where extracted files locate"\
+ % target_name)
+
+ if not os.path.exists(target_name):
+ os.makedirs(target_name)
+
+ _extract_tarball(archive_name, target_name)
+
+packing = make_archive
+compressing = compress
+
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2009, 2010, 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+from __future__ import with_statement
+import os
+import sys
+import tempfile
+import shutil
+import subprocess
+import rpm
+import glob
+import errno
+
+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"
+
+RPMTRANS_FLAGS = [
+ rpm.RPMTRANS_FLAG_ALLFILES,
+ rpm.RPMTRANS_FLAG_NOSCRIPTS,
+ rpm.RPMTRANS_FLAG_NOTRIGGERS,
+ ]
+
+RPMVSF_FLAGS = [
+ rpm._RPMVSF_NOSIGNATURES,
+ rpm._RPMVSF_NODIGESTS
+ ]
+
+RPMPROB_FLAGS = [
+ rpm.RPMPROB_FILTER_OLDPACKAGE,
+ rpm.RPMPROB_FILTER_REPLACEPKG,
+ rpm.RPMPROB_FILTER_IGNOREARCH
+ ]
+
+class MiniBackend(object):
+ def __init__(self, rootdir, arch=None, repomd=None):
+ self._ts = None
+ self.rootdir = os.path.abspath(rootdir)
+ self.arch = arch
+ self.repomd = repomd
+ self.dlpkgs = []
+ self.localpkgs = {}
+ self.optionals = []
+ self.preins = {}
+ self.postins = {}
+ self.scriptlets = False
+
+ def __del__(self):
+ try:
+ del self.ts
+ except:
+ pass
+
+ def get_ts(self):
+ if not self._ts:
+ self._ts = rpm.TransactionSet(self.rootdir)
+ self._ts.setFlags(reduce(lambda x, y: x|y, RPMTRANS_FLAGS))
+ self._ts.setVSFlags(reduce(lambda x, y: x|y, RPMVSF_FLAGS))
+ self._ts.setProbFilter(reduce(lambda x, y: x|y, RPMPROB_FLAGS))
+
+ return self._ts
+
+ def del_ts(self):
+ if self._ts:
+ self._ts.closeDB()
+ self._ts = None
+
+ ts = property(fget = lambda self: self.get_ts(),
+ fdel = lambda self: self.del_ts(),
+ doc="TransactionSet object")
+
+ def selectPackage(self, pkg):
+ 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()
+ self.installPkgs()
+
+ if not self.scriptlets:
+ return
+
+ for pkg in self.preins.keys():
+ prog, script = self.preins[pkg]
+ self.run_pkg_script(pkg, prog, script, '0')
+ for pkg in self.postins.keys():
+ prog, script = self.postins[pkg]
+ self.run_pkg_script(pkg, prog, script, '1')
+
+ def downloadPkgs(self):
+ nonexist = []
+ for pkg in self.dlpkgs:
+ 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:
+ # skip optional rpm
+ continue
+ else:
+ # mark nonexist rpm
+ nonexist.append(pkg)
+
+ if nonexist:
+ raise errors.BootstrapError("Can't get rpm binary: %s" %
+ ','.join(nonexist))
+
+ def installPkgs(self):
+ for pkg in self.localpkgs.keys():
+ rpmpath = self.localpkgs[pkg]
+
+ hdr = readRpmHeader(self.ts, rpmpath)
+
+ # save prein and postin scripts
+ self.preins[pkg] = (hdr['PREINPROG'], hdr['PREIN'])
+ self.postins[pkg] = (hdr['POSTINPROG'], hdr['POSTIN'])
+
+ # mark pkg as install
+ self.ts.addInstall(hdr, rpmpath, 'u')
+
+ # run transaction
+ self.ts.order()
+ cb = RPMInstallCallback(self.ts)
+ errs = self.ts.run(cb.callback, '')
+
+ # ts.run() exit codes are, hmm, "creative": None means all ok, empty
+ # list means some errors happened in the transaction and non-empty
+ # list that there were errors preventing the ts from starting...
+ if errs is not None:
+ raise errors.BootstrapError("Transaction couldn't start: %s" % errs)
+
+ def run_pkg_script(self, pkg, prog, script, arg):
+ mychroot = lambda: os.chroot(self.rootdir)
+
+ if not script:
+ return
+
+ if prog == "<lua>":
+ prog = "/usr/bin/lua"
+
+ tmpdir = os.path.join(self.rootdir, "tmp")
+ if not os.path.exists(tmpdir):
+ os.makedirs(tmpdir)
+ tmpfd, tmpfp = tempfile.mkstemp(dir=tmpdir, prefix="%s.pre-" % pkg)
+ script = script.replace('\r', '')
+ os.write(tmpfd, script)
+ os.close(tmpfd)
+ os.chmod(tmpfp, 0o700)
+
+ try:
+ script_fp = os.path.join('/tmp', os.path.basename(tmpfp))
+ subprocess.call([prog, script_fp, arg], preexec_fn=mychroot)
+ except (OSError, IOError) as err:
+ msger.warning(str(err))
+ finally:
+ os.unlink(tmpfp)
+
+class Bootstrap(object):
+ def __init__(self, rootdir, distro, arch=None):
+ self.rootdir = misc.mkdtemp(dir=rootdir, prefix=distro)
+ self.distro = distro
+ self.arch = arch
+ self.logfile = None
+ self.pkgslist = []
+ self.repomd = None
+
+ def __del__(self):
+ self.cleanup()
+
+ def get_rootdir(self):
+ if os.path.exists(self.rootdir):
+ shutil.rmtree(self.rootdir, ignore_errors=True)
+ os.makedirs(self.rootdir)
+ return self.rootdir
+
+ def dirsetup(self, rootdir=None):
+ _path = lambda pth: os.path.join(rootdir, pth.lstrip('/'))
+
+ if not rootdir:
+ rootdir = self.rootdir
+
+ try:
+ # make /tmp and /etc path
+ tmpdir = _path('/tmp')
+ if not os.path.exists(tmpdir):
+ os.makedirs(tmpdir)
+ etcdir = _path('/etc')
+ if not os.path.exists(etcdir):
+ os.makedirs(etcdir)
+
+ # touch distro file
+ tzdist = _path('/etc/%s-release' % self.distro)
+ if not os.path.exists(tzdist):
+ with open(tzdist, 'w') as wf:
+ wf.write("bootstrap")
+ except:
+ pass
+
+ def create(self, repomd, pkglist, optlist=()):
+ try:
+ pkgmgr = MiniBackend(self.get_rootdir())
+ pkgmgr.arch = self.arch
+ pkgmgr.repomd = repomd
+ pkgmgr.optionals = list(optlist)
+ map(pkgmgr.selectPackage, pkglist + list(optlist))
+ pkgmgr.runInstall()
+ except (OSError, IOError, errors.CreatorError) as err:
+ raise errors.BootstrapError("%s" % err)
+
+ def run(self, cmd, chdir, rootdir=None, bindmounts=None):
+ def mychroot():
+ os.chroot(rootdir)
+ os.chdir(chdir)
+
+ def sync_timesetting(rootdir):
+ try:
+ # sync time and zone info to bootstrap
+ if os.path.exists(rootdir + "/etc/localtime"):
+ os.unlink(rootdir + "/etc/localtime")
+ shutil.copyfile("/etc/localtime", rootdir + "/etc/localtime")
+ except:
+ pass
+
+ def sync_passwdfile(rootdir):
+ try:
+ # sync passwd file to bootstrap, saving the user info
+ if os.path.exists(rootdir + "/etc/passwd"):
+ os.unlink(rootdir + "/etc/passwd")
+ shutil.copyfile("/etc/passwd", rootdir + "/etc/passwd")
+ 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
+
+ if isinstance(cmd, list):
+ shell = False
+ else:
+ shell = True
+
+ 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
+ try:
+ proxy.set_proxy_environ()
+ #globalmounts is no useless, remove it, currently function always return none.
+ 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
+ value, tb = sys.exc_info()[1:]
+ value = '%s: %s' % (value, ' '.join(cmd))
+ raise RuntimeError (value, tb)
+ finally:
+ #if self.logfile and os.path.isfile(self.logfile):
+ # msger.log(file(self.logfile).read())
+ cleanup_chrootenv(rootdir, bindmounts, gloablmounts)
+ proxy.unset_proxy_environ()
+ return retcode
+
+ def cleanup(self):
+ try:
+ # clean mounts
+ cleanup_mounts(self.rootdir)
+ # remove rootdir
+ shutil.rmtree(self.rootdir, ignore_errors=True)
+ except:
+ pass
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2009, 2010, 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+from __future__ import with_statement
+import os
+import re
+import shutil
+import subprocess
+
+from mic import msger
+from mic.conf import configmgr
+from mic.utils import misc, errors, runner, fs_related, lock
+
+#####################################################################
+### GLOBAL CONSTANTS
+#####################################################################
+
+chroot_bindmounts = None
+chroot_lock = None
+BIND_MOUNTS = (
+ "/proc",
+ "/proc/sys/fs/binfmt_misc",
+ "/sys",
+ "/dev",
+ "/dev/pts",
+ "/var/lib/dbus",
+ "/var/run/dbus",
+ "/var/lock",
+ "/lib/modules",
+ )
+
+#####################################################################
+### GLOBAL ROUTINE
+#####################################################################
+
+def ELF_arch(chrootdir):
+ """ detect the architecture of an ELF file """
+ #FIXME: if chkfiles are symlink, it will be complex
+ chkfiles = ('/bin/bash', '/sbin/init')
+ # regular expression to arch mapping
+ mapping = {
+ r"Intel 80[0-9]86": "i686",
+ r"x86-64": "x86_64",
+ r"ARM": "arm",
+ r"RISC-V": "riscv64",
+ }
+
+ for path in chkfiles:
+ cpath = os.path.join(chrootdir, path.lstrip('/'))
+ if not os.path.exists(cpath):
+ continue
+
+ outs = runner.outs(['file', cpath])
+ for ptn in mapping.keys():
+ if re.search(ptn, outs):
+ return mapping[ptn]
+
+ raise errors.CreatorError("Failed to detect architecture of chroot: %s" %
+ chrootdir)
+
+def get_bindmounts(chrootdir, bindmounts = None):
+ """ calculate all bind mount entries for global usage """
+ # bindmounts should be a string like '/dev:/dev'
+ # FIXME: refine the bindmounts from string to dict
+ global chroot_bindmounts
+
+ def totuple(string):
+ """ convert string contained ':' to a tuple """
+ if ':' in string:
+ src, dst = string.split(':', 1)
+ else:
+ src = string
+ dst = None
+
+ return (src or None, dst or None)
+
+ if chroot_bindmounts:
+ return chroot_bindmounts
+
+ chroot_bindmounts = []
+ bindmounts = bindmounts or ""
+ mountlist = []
+
+ for mount in bindmounts.split(";"):
+ if not mount:
+ continue
+
+ (src, dst) = totuple(mount)
+
+ if src in BIND_MOUNTS or src == '/':
+ continue
+
+ if not os.path.exists(src):
+ os.makedirs(src)
+
+ if dst and os.path.isdir("%s/%s" % (chrootdir, dst)):
+ msger.warning("%s existed in %s , skip it." % (dst, chrootdir))
+ continue
+
+ mountlist.append(totuple(mount))
+
+ for mntpoint in BIND_MOUNTS:
+ if os.path.isdir(mntpoint):
+ mountlist.append(tuple((mntpoint, None)))
+
+ for pair in mountlist:
+ if pair[0] == "/lib/modules":
+ opt = "ro"
+ else:
+ opt = None
+ bmount = fs_related.BindChrootMount(pair[0], chrootdir, pair[1], opt)
+ chroot_bindmounts.append(bmount)
+
+ return chroot_bindmounts
+
+#####################################################################
+### SETUP CHROOT ENVIRONMENT
+#####################################################################
+
+def bind_mount(chrootmounts):
+ """ perform bind mounting """
+ for mnt in chrootmounts:
+ msger.verbose("bind_mount: %s -> %s" % (mnt.src, mnt.dest))
+ mnt.mount()
+
+def setup_resolv(chrootdir):
+ """ resolve network """
+ try:
+ shutil.copyfile("/etc/resolv.conf", chrootdir + "/etc/resolv.conf")
+ except (OSError, IOError):
+ pass
+
+def setup_mtab(chrootdir):
+ """ adjust mount table """
+ try:
+ mtab = "/etc/mtab"
+ dstmtab = chrootdir + mtab
+ if not os.path.islink(dstmtab):
+ shutil.copyfile(mtab, dstmtab)
+ except (OSError, IOError):
+ pass
+
+def setup_chrootenv(chrootdir, bindmounts = None):
+ """ setup chroot environment """
+ global chroot_lock
+
+ # acquire the lock
+ if not chroot_lock:
+ lockpath = os.path.join(chrootdir, '.chroot.lock')
+ chroot_lock = lock.SimpleLockfile(lockpath)
+ chroot_lock.acquire()
+ # bind mounting
+ bind_mount(get_bindmounts(chrootdir, bindmounts))
+ # setup resolv.conf
+ setup_resolv(chrootdir)
+ # update /etc/mtab
+ setup_mtab(chrootdir)
+
+ return None
+
+######################################################################
+### CLEANUP CHROOT ENVIRONMENT
+######################################################################
+
+def bind_unmount(chrootmounts):
+ """ perform bind unmounting """
+ for mnt in reversed(chrootmounts):
+ msger.verbose("bind_unmount: %s -> %s" % (mnt.src, mnt.dest))
+ mnt.unmount()
+
+def cleanup_resolv(chrootdir):
+ """ clear resolv.conf """
+ try:
+ fdes = open(chrootdir + "/etc/resolv.conf", "w")
+ fdes.truncate(0)
+ fdes.close()
+ except (OSError, IOError):
+ pass
+
+def kill_proc_inchroot(chrootdir):
+ """ kill all processes running inside chrootdir """
+ import glob
+ for fpath in glob.glob("/proc/*/root"):
+ try:
+ if os.readlink(fpath) == chrootdir:
+ pid = int(fpath.split("/")[2])
+ os.kill(pid, 9)
+ except (OSError, ValueError):
+ pass
+
+def cleanup_mtab(chrootdir):
+ """ remove mtab file """
+ if os.path.exists(chrootdir + "/etc/mtab"):
+ os.unlink(chrootdir + "/etc/mtab")
+
+def cleanup_mounts(chrootdir):
+ """ clean up all mount entries owned by chrootdir """
+ umountcmd = misc.find_binary_path("umount")
+ mounts = open('/proc/mounts').readlines()
+ for line in reversed(mounts):
+ if chrootdir not in line:
+ continue
+
+ point = line.split()[1]
+
+ # '/' to avoid common name prefix
+ if chrootdir == point or point.startswith(chrootdir + '/'):
+ args = [ umountcmd, "-l", point ]
+ ret = runner.quiet(args)
+ if ret != 0:
+ msger.warning("failed to unmount %s" % point)
+ if os.path.isdir(point) and len(os.listdir(point)) == 0:
+ shutil.rmtree(point)
+ else:
+ msger.warning("%s is not directory or is not empty" % point)
+
+def cleanup_chrootenv(chrootdir, bindmounts=None, globalmounts=()):
+ """ clean up chroot environment """
+ global chroot_lock
+
+ # kill processes
+ kill_proc_inchroot(chrootdir)
+ # clean mtab
+ cleanup_mtab(chrootdir)
+ # clean resolv.conf
+ cleanup_resolv(chrootdir)
+ # bind umounting
+ bind_unmount(get_bindmounts(chrootdir, bindmounts))
+ # FIXME: need to clean up mounts?
+ #cleanup_mounts(chrootdir)
+
+ # release the lock
+ if chroot_lock:
+ chroot_lock.release()
+ chroot_lock = None
+
+ return None
+
+#####################################################################
+### CHROOT STUFF
+#####################################################################
+
+def savefs_before_chroot(chrootdir, saveto = None):
+ """ backup chrootdir to another directory before chrooting in """
+ if configmgr.chroot['saveto']:
+ savefs = True
+ saveto = configmgr.chroot['saveto']
+ wrnmsg = "Can't save chroot fs for dir %s exists" % saveto
+ if saveto == chrootdir:
+ savefs = False
+ wrnmsg = "Dir %s is being used to chroot" % saveto
+ elif os.path.exists(saveto):
+ if msger.ask("Dir %s already exists, cleanup and continue?" %
+ saveto):
+ shutil.rmtree(saveto, ignore_errors = True)
+ savefs = True
+ else:
+ savefs = False
+
+ if savefs:
+ msger.info("Saving image to directory %s" % saveto)
+ fs_related.makedirs(os.path.dirname(os.path.abspath(saveto)))
+ runner.quiet("cp -af %s %s" % (chrootdir, saveto))
+ devs = ['dev/fd',
+ 'dev/stdin',
+ 'dev/stdout',
+ 'dev/stderr',
+ 'etc/mtab']
+ ignlst = [os.path.join(saveto, x) for x in devs]
+ map(os.unlink, filter(os.path.exists, ignlst))
+ else:
+ msger.warning(wrnmsg)
+
+def cleanup_after_chroot(targettype, imgmount, tmpdir, tmpmnt):
+ """ clean up all temporary directories after chrooting """
+ if imgmount and targettype == "img":
+ imgmount.cleanup()
+
+ if tmpdir:
+ shutil.rmtree(tmpdir, ignore_errors = True)
+
+ if tmpmnt:
+ shutil.rmtree(tmpmnt, ignore_errors = True)
+
+def chroot(chrootdir, bindmounts = None, execute = "/bin/bash"):
+ """ chroot the chrootdir and execute the command """
+ def mychroot():
+ """ pre-execute function """
+ os.chroot(chrootdir)
+ os.chdir("/")
+
+ arch = ELF_arch(chrootdir)
+ if arch == "arm":
+ qemu_emulators = misc.setup_qemu_emulator(chrootdir, "arm")
+ elif arch == "mipsel":
+ qemu_emulators = misc.setup_qemu_emulator(chrootdir, "mipsel")
+ elif arch == "riscv64":
+ qemu_emulators = misc.setup_qemu_emulator(chrootdir, "riscv64")
+ else:
+ qemu_emulators = []
+
+ savefs_before_chroot(chrootdir, None)
+
+ globalmounts = None
+
+ try:
+ msger.info("Launching shell. Exit to continue.\n"
+ "----------------------------------")
+
+ #globalmounts is no useless, remove it, currently function always return none.
+ setup_chrootenv(chrootdir, bindmounts)
+ subprocess.call(execute, preexec_fn = mychroot, shell=True)
+
+ except OSError as err:
+ raise errors.CreatorError("chroot err: %s" % str(err))
+
+ finally:
+ cleanup_chrootenv(chrootdir, bindmounts, globalmounts)
+ for qemu_emulator in qemu_emulators:
+ os.unlink(chrootdir + qemu_emulator)
--- /dev/null
+#!/usr/bin/python -tt\r
+# vim: ai ts=4 sts=4 et sw=4\r
+#\r
+# Copyright (c) 2012 Intel, Inc.\r
+#\r
+# This program is free software; you can redistribute it and/or modify it\r
+# under the terms of the GNU General Public License as published by the Free\r
+# Software Foundation; version 2 of the License\r
+#\r
+# This program is distributed in the hope that it will be useful, but\r
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\r
+# for more details.\r
+#\r
+# You should have received a copy of the GNU General Public License along\r
+# with this program; if not, write to the Free Software Foundation, Inc., 59\r
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
+\r
+"""Implementation of subcmd: chroot\r
+"""\r
+\r
+import os\r
+import os, sys, re\r
+import pwd\r
+import argparse\r
+\r
+from mic import msger\r
+from mic.utils import misc, errors\r
+from mic.conf import configmgr\r
+from mic.plugin import pluginmgr\r
+\r
+def _root_confirm():\r
+ """Make sure command is called by root\r
+ There are a lot of commands needed to be run during creating images,\r
+ some of them must be run with root privilege like mount, kpartx"""\r
+ if os.geteuid() != 0:\r
+ msger.error('Root permission is required to continue, abort')\r
+ \r
+def main(parser, args, argv):\r
+ """mic choot entry point."""\r
+\r
+ #args is argparser namespace, argv is the input cmd line\r
+ if args is None:\r
+ raise errors.Usage("Invalid arguments")\r
+\r
+ targetimage = args.imagefile\r
+ if not os.path.exists(targetimage):\r
+ raise errors.CreatorError("Cannot find the image: %s"\r
+ % targetimage)\r
+\r
+ _root_confirm()\r
+\r
+ configmgr.chroot['saveto'] = args.saveto\r
+\r
+ imagetype = misc.get_image_type(targetimage)\r
+ if imagetype in ("ext3fsimg", "ext4fsimg", "btrfsimg", "f2fsimg"):\r
+ imagetype = "loop"\r
+\r
+ chrootclass = None\r
+ for pname, pcls in pluginmgr.get_plugins('imager').iteritems():\r
+ if pname == imagetype and hasattr(pcls, "do_chroot"):\r
+ chrootclass = pcls\r
+ break\r
+\r
+ if not chrootclass:\r
+ raise errors.CreatorError("Cannot support image type: %s" \\r
+ % imagetype)\r
+\r
+ chrootclass.do_chroot(targetimage, args.cmd)\r
+ \r
+ \r
--- /dev/null
+#!/usr/bin/python -tt\r
+# vim: ai ts=4 sts=4 et sw=4\r
+#\r
+# Copyright (c) 2012 Intel, Inc.\r
+#\r
+# This program is free software; you can redistribute it and/or modify it\r
+# under the terms of the GNU General Public License as published by the Free\r
+# Software Foundation; version 2 of the License\r
+#\r
+# This program is distributed in the hope that it will be useful, but\r
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\r
+# for more details.\r
+#\r
+# You should have received a copy of the GNU General Public License along\r
+# with this program; if not, write to the Free Software Foundation, Inc., 59\r
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
+\r
+"""Implementation of subcmd: create\r
+"""\r
+\r
+import os\r
+import os, sys, re\r
+import pwd\r
+import argparse\r
+\r
+from mic import msger\r
+from mic.utils import errors, rpmmisc\r
+from mic.conf import configmgr\r
+from mic.plugin import pluginmgr\r
+\r
+def main(parser, args, argv):\r
+ """mic create entry point."""\r
+ #args is argparser namespace, argv is the input cmd line\r
+ if args is None:\r
+ raise errors.Usage("Invalid arguments")\r
+\r
+ if not os.path.exists(args.ksfile):\r
+ raise errors.CreatorError("Can't find the file: %s" % args.ksfile)\r
+\r
+ if os.geteuid() != 0:\r
+ msger.error("Root permission is required, abort")\r
+ \r
+ try:\r
+ w = pwd.getpwuid(os.geteuid())\r
+ except KeyError:\r
+ msger.warning("Might fail in compressing stage for undetermined user")\r
+ \r
+ abspath = lambda pth: os.path.abspath(os.path.expanduser(pth))\r
+ if args.logfile:\r
+ logfile_abs_path = abspath(args.logfile)\r
+ if os.path.isdir(logfile_abs_path):\r
+ raise errors.Usage("logfile's path %s should be file"\r
+ % args.logfile)\r
+ configmgr.create['logfile'] = logfile_abs_path\r
+ configmgr.set_logfile()\r
+\r
+ if args.subcommand == "auto":\r
+ do_auto(parser, args.ksfile, argv)\r
+ return\r
+\r
+ if args.interactive:\r
+ msger.enable_interactive()\r
+ else:\r
+ msger.disable_interactive()\r
+\r
+ if args.verbose:\r
+ msger.set_loglevel('VERBOSE')\r
+\r
+ if args.debug:\r
+ try:\r
+ import rpm\r
+ rpm.setVerbosity(rpm.RPMLOG_NOTICE)\r
+ except ImportError:\r
+ pass\r
+\r
+ msger.set_loglevel('DEBUG')\r
+\r
+ if args.rpm_debug:\r
+ try:\r
+ import rpm\r
+ rpm.setVerbosity(rpm.RPMLOG_DEBUG)\r
+ except ImportError:\r
+ pass\r
+ #check the imager type\r
+ createrClass = None\r
+ for subcmd, klass in pluginmgr.get_plugins('imager').iteritems():\r
+ if subcmd == args.subcommand and hasattr(klass, 'do_create'):\r
+ createrClass = klass\r
+\r
+ if createrClass is None:\r
+ raise errors.CreatorError("Can't support subcommand %s" % args.subcommand)\r
+\r
+ if args.config:\r
+ configmgr.reset()\r
+ configmgr._siteconf = args.config\r
+\r
+ if args.outdir is not None:\r
+ configmgr.create['outdir'] = abspath(args.outdir)\r
+ if args.cachedir is not None:\r
+ configmgr.create['cachedir'] = abspath(args.cachedir)\r
+ os.environ['ZYPP_LOCKFILE_ROOT'] = configmgr.create['cachedir']\r
+\r
+ for cdir in ('outdir', 'cachedir'):\r
+ if os.path.exists(configmgr.create[cdir]) \\r
+ and not os.path.isdir(configmgr.create[cdir]):\r
+ raise errors.Usage('Invalid directory specified: %s' \\r
+ % configmgr.create[cdir])\r
+ if not os.path.exists(configmgr.create[cdir]):\r
+ os.makedirs(configmgr.create[cdir])\r
+ if os.getenv('SUDO_UID', '') and os.getenv('SUDO_GID', ''):\r
+ os.chown(configmgr.create[cdir],\r
+ int(os.getenv('SUDO_UID')),\r
+ int(os.getenv('SUDO_GID')))\r
+\r
+ if args.local_pkgs_path is not None:\r
+ if not os.path.exists(args.local_pkgs_path):\r
+ raise errors.Usage('Local pkgs directory: \'%s\' not exist' \\r
+ % args.local_pkgs_path)\r
+ configmgr.create['local_pkgs_path'] = args.local_pkgs_path\r
+\r
+ if args.release:\r
+ configmgr.create['release'] = args.release.rstrip('/')\r
+\r
+ if args.record_pkgs:\r
+ configmgr.create['record_pkgs'] = []\r
+ for infotype in args.record_pkgs.split(','):\r
+ if infotype not in ('name', 'content', 'license', 'vcs'):\r
+ raise errors.Usage('Invalid pkg recording: %s, valid ones:'\r
+ ' "name", "content", "license", "vcs"' \\r
+ % infotype)\r
+\r
+ configmgr.create['record_pkgs'].append(infotype)\r
+\r
+ if args.strict_mode:\r
+ configmgr.create['strict_mode'] = args.strict_mode\r
+ if args.arch is not None:\r
+ supported_arch = sorted(rpmmisc.archPolicies.keys(), reverse=True)\r
+ if args.arch in supported_arch:\r
+ configmgr.create['arch'] = args.arch\r
+ else:\r
+ raise errors.Usage('Invalid architecture: "%s".\n'\r
+ ' Supported architectures are: \n'\r
+ ' %s' % (args.arch,\r
+ ', '.join(supported_arch)))\r
+\r
+ if args.pkgmgr is not None:\r
+ configmgr.create['pkgmgr'] = args.pkgmgr\r
+\r
+ if args.skip_set_hosts:\r
+ configmgr.create['skip_set_hosts']=args.skip_set_hosts\r
+ if args.postscripts_maxruntime:\r
+ configmgr.create['postscripts_maxruntime']=int(args.postscripts_maxruntime)\r
+ if args.block_recommends:\r
+ configmgr.create['block_recommends']=args.block_recommends\r
+ if args.runtime:\r
+ configmgr.set_runtime(args.runtime)\r
+\r
+ if args.use_mic_in_bootstrap:\r
+ configmgr.create['use_mic_in_bootstrap'] = args.use_mic_in_bootstrap\r
+\r
+ if args.pack_to is not None:\r
+ configmgr.create['pack_to'] = args.pack_to\r
+\r
+ if args.copy_kernel:\r
+ configmgr.create['copy_kernel'] = args.copy_kernel\r
+\r
+ if args.install_pkgs:\r
+ configmgr.create['install_pkgs'] = []\r
+ for pkgtype in args.install_pkgs.split(','):\r
+ if pkgtype not in ('source', 'debuginfo', 'debugsource'):\r
+ raise errors.Usage('Invalid parameter specified: "%s", '\r
+ 'valid values: source, debuginfo, '\r
+ 'debusource' % pkgtype)\r
+\r
+ configmgr.create['install_pkgs'].append(pkgtype)\r
+\r
+ if args.check_pkgs:\r
+ for pkg in args.check_pkgs.split(','):\r
+ configmgr.create['check_pkgs'].append(pkg)\r
+\r
+ if args.enabletmpfs:\r
+ configmgr.create['enabletmpfs'] = args.enabletmpfs\r
+\r
+ if args.repourl:\r
+ for item in args.repourl:\r
+ try:\r
+ key, val = item.split('=')\r
+ except:\r
+ continue\r
+ configmgr.create['repourl'][key] = val\r
+\r
+ if args.repo:\r
+ for optvalue in args.repo:\r
+ repo = {}\r
+ for item in optvalue.split(';'):\r
+ try:\r
+ key, val = item.split('=')\r
+ except:\r
+ continue\r
+ repo[key.strip()] = val.strip()\r
+ if 'name' in repo:\r
+ configmgr.create['extrarepos'][repo['name']] = repo\r
+\r
+ if args.ignore_ksrepo:\r
+ configmgr.create['ignore_ksrepo'] = args.ignore_ksrepo\r
+ if args.run_script:\r
+ configmgr.create['run_script'] = args.run_script\r
+ if args.tpk_install:\r
+ configmgr.create['tpk_install'] = args.tpk_install\r
+\r
+ creater = createrClass()\r
+ creater.do_create(args)\r
+\r
+def do_auto(parser, ksfile, argv):\r
+ """${cmd_name}: auto detect image type from magic header\r
+\r
+ Usage:\r
+ ${name} ${cmd_name} <ksfile>\r
+\r
+ ${cmd_option_list}\r
+ """\r
+ def parse_magic_line(re_str, pstr, ptype='mic'):\r
+ ptn = re.compile(re_str)\r
+ m = ptn.match(pstr)\r
+ if not m or not m.groups():\r
+ return None\r
+\r
+ inline_argv = m.group(1).strip()\r
+ if ptype == 'mic':\r
+ m2 = re.search('(?P<format>\w+)', inline_argv)\r
+ elif ptype == 'mic2':\r
+ m2 = re.search('(-f|--format(=)?)\s*(?P<format>\w+)',\r
+ inline_argv)\r
+ else:\r
+ return None\r
+\r
+ if m2:\r
+ cmdname = m2.group('format')\r
+ inline_argv = inline_argv.replace(m2.group(0), '')\r
+ return (cmdname, inline_argv)\r
+\r
+ return None\r
+\r
+ if not os.path.exists(ksfile):\r
+ raise errors.CreatorError("Can't find the file: %s" % ksfile)\r
+\r
+ with open(ksfile, 'r') as rf:\r
+ first_line = rf.readline()\r
+\r
+ mic_re = '^#\s*-\*-mic-options-\*-\s+(.*)\s+-\*-mic-options-\*-'\r
+ mic2_re = '^#\s*-\*-mic2-options-\*-\s+(.*)\s+-\*-mic2-options-\*-'\r
+\r
+ result = parse_magic_line(mic_re, first_line, 'mic') \\r
+ or parse_magic_line(mic2_re, first_line, 'mic2')\r
+ if not result:\r
+ raise errors.KsError("Invalid magic line in file: %s" % ksfile)\r
+ \r
+ ksargv = ' '.join(result).split()\r
+\r
+ argv.remove("auto")\r
+ index = argv.index("create")\r
+ #insert the subcommand\r
+ argv.insert(index+1, ksargv[0])\r
+ options = argv + ksargv[1:]\r
+\r
+ args = parser.parse_args(options)\r
+\r
+ main(parser, args, options)\r
+\r
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os, sys, re
+import ConfigParser
+
+from mic import msger
+from mic import kickstart
+from mic.utils import misc, runner, proxy, errors
+
+
+DEFAULT_GSITECONF = '/etc/mic/mic.conf'
+
+
+def get_siteconf():
+ if hasattr(sys, 'real_prefix'):
+ return os.path.join(sys.prefix, "etc/mic/mic.conf")
+ else:
+ return DEFAULT_GSITECONF
+
+def inbootstrap():
+ if os.path.exists(os.path.join("/", ".chroot.lock")):
+ return True
+ return (os.stat("/").st_ino != 2)
+
+class ConfigMgr(object):
+ prefer_backends = ["zypp", "yum"]
+
+ DEFAULTS = {'common': {
+ "distro_name": "Default Distribution",
+ "plugin_dir": "/usr/lib/mic/plugins", # TODO use prefix also?
+ },
+ 'create': {
+ "tmpdir": '/var/tmp/mic',
+ "cachedir": '/var/tmp/mic/cache',
+ "outdir": './mic-output',
+ "destdir": None,
+ "arch": None, # None means auto-detect
+ "pkgmgr": "auto",
+ "name": "output",
+ "ksfile": None,
+ "ks": None,
+ "repomd": None,
+ "local_pkgs_path": None,
+ "release": None,
+ "logfile": None,
+ "releaselog": False,
+ "record_pkgs": [],
+ "pack_to": None,
+ "name_prefix": None,
+ "name_suffix": None,
+ "proxy": None,
+ "no_proxy": None,
+ "ssl_verify": "yes",
+ "copy_kernel": False,
+ "install_pkgs": None,
+ "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,
+ "skip_set_hosts": False,
+ "postscripts_maxruntime": 120,
+ "block_recommends": False,
+ },
+ 'chroot': {
+ "saveto": None,
+ },
+ 'convert': {
+ "shell": False,
+ },
+ 'bootstrap': {
+ "rootdir": '/var/tmp/mic-bootstrap',
+ "packages": [],
+ "distro_name": "",
+ },
+ }
+
+ # make the manager class as singleton
+ _instance = None
+ def __new__(cls, *args, **kwargs):
+ if not cls._instance:
+ cls._instance = super(ConfigMgr, cls).__new__(cls, *args, **kwargs)
+
+ return cls._instance
+
+ def __init__(self, ksconf=None, siteconf=None):
+ # reset config options
+ self.reset()
+
+ if not siteconf:
+ siteconf = get_siteconf()
+
+ # initial options from siteconf
+ self._siteconf = siteconf
+
+ if ksconf:
+ self._ksconf = ksconf
+
+ def reset(self):
+ self.__ksconf = None
+ self.__siteconf = None
+
+ # initialize the values with defaults
+ for sec, vals in self.DEFAULTS.iteritems():
+ setattr(self, sec, vals)
+
+ def __set_siteconf(self, siteconf):
+ try:
+ self.__siteconf = siteconf
+ self._parse_siteconf(siteconf)
+ except ConfigParser.Error as error:
+ raise errors.ConfigError("%s" % error)
+ def __get_siteconf(self):
+ return self.__siteconf
+ _siteconf = property(__get_siteconf, __set_siteconf)
+
+ def __set_ksconf(self, ksconf):
+ if not os.path.isfile(ksconf):
+ raise errors.KsError('Cannot find ks file: %s' % ksconf)
+
+ self.__ksconf = ksconf
+ self._parse_kickstart(ksconf)
+ def __get_ksconf(self):
+ return self.__ksconf
+ _ksconf = property(__get_ksconf, __set_ksconf)
+
+ def _parse_siteconf(self, siteconf):
+
+ if os.getenv("MIC_PLUGIN_DIR"):
+ self.common["plugin_dir"] = os.environ["MIC_PLUGIN_DIR"]
+
+ if siteconf and not os.path.exists(siteconf):
+ msger.warning("cannot find config file: %s" % siteconf)
+ siteconf = None
+
+ if not siteconf:
+ self.common["distro_name"] = "Tizen"
+ # append common section items to other sections
+ for section in self.DEFAULTS.keys():
+ if section != "common":
+ getattr(self, section).update(self.common)
+
+ return
+
+ parser = ConfigParser.SafeConfigParser()
+ parser.read(siteconf)
+
+ for section in parser.sections():
+ if section in self.DEFAULTS:
+ getattr(self, section).update(dict(parser.items(section)))
+
+ # append common section items to other sections
+ for section in self.DEFAULTS.keys():
+ if section != "common":
+ getattr(self, section).update(self.common)
+
+ # check and normalize the scheme of proxy url
+ if self.create['proxy']:
+ m = re.match('^(\w+)://.*', self.create['proxy'])
+ if m:
+ scheme = m.group(1)
+ if scheme not in ('http', 'https', 'ftp', 'socks'):
+ raise errors.ConfigError("%s: proxy scheme is incorrect" % siteconf)
+ else:
+ msger.warning("%s: proxy url w/o scheme, use http as default"
+ % siteconf)
+ self.create['proxy'] = "http://" + self.create['proxy']
+
+ proxy.set_proxies(self.create['proxy'], self.create['no_proxy'])
+
+ # bootstrap option handling
+ self.set_runtime(self.create['runtime'])
+ if isinstance(self.bootstrap['packages'], basestring):
+ packages = self.bootstrap['packages'].replace('\n', ' ')
+ if packages.find(',') != -1:
+ packages = packages.split(',')
+ else:
+ 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
+
+ ksconf = misc.normalize_ksfile(ksconf,
+ self.create['release'],
+ self.create['arch'])
+
+ ks = kickstart.read_kickstart(ksconf)
+
+ self.create['ks'] = ks
+ self.create['name'] = os.path.splitext(os.path.basename(ksconf))[0]
+
+ self.create['name'] = misc.build_name(ksconf,
+ self.create['release'],
+ self.create['name_prefix'],
+ self.create['name_suffix'])
+
+ self.create['destdir'] = self.create['outdir']
+ if self.create['release'] is not None:
+ self.create['destdir'] = "%s/%s/images/%s/" % (self.create['outdir'],
+ 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'],
+ self.create['name'] + ".log")
+ 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'],
+ self.create['ignore_ksrepo'])
+ if not ksrepos:
+ raise errors.KsError('no valid repos found in ks file')
+
+ for repo in ksrepos:
+ if hasattr(repo, 'baseurl') and repo.baseurl.startswith("file:"):
+ repourl = repo.baseurl.replace('file:', '')
+ repourl = "/%s" % repourl.lstrip('/')
+ self.create['localrepos'].append(repourl)
+
+ 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'])
+ if self.create['arch']:
+ if self.create['arch'] not in archlist:
+ raise errors.ConfigError("Invalid arch %s for repository. "
+ "Valid arches: %s" \
+ % (self.create['arch'], ', '.join(archlist)))
+ else:
+ if len(target_archlist) == 1:
+ self.create['arch'] = str(target_archlist[0])
+ msger.info("Use detected arch %s." % target_archlist[0])
+ else:
+ raise errors.ConfigError("Please specify a valid arch, "
+ "the choice can be: %s" \
+ % ', '.join(archlist))
+
+ kickstart.resolve_groups(self.create, self.create['repomd'])
+
+ # check selinux, it will block arm and btrfs image creation
+ misc.selinux_check(self.create['arch'],
+ [p.fstype for p in ks.handler.partition.partitions])
+
+ def set_logfile(self, logfile = None):
+ if not logfile:
+ logfile = self.create['logfile']
+
+ logfile_dir = os.path.dirname(self.create['logfile'])
+ if not os.path.exists(logfile_dir):
+ os.makedirs(logfile_dir)
+ msger.set_interactive(False)
+ if inbootstrap():
+ mode = 'a'
+ else:
+ mode = 'w'
+ msger.set_logfile(self.create['logfile'], mode)
+
+ def set_runtime(self, runtime):
+ if runtime != "bootstrap":
+ raise errors.CreatorError("Invalid runtime mode: %s, only 'bootstrap' mode is allowed." % runtime)
+
+ if misc.get_distro()[0] in ("tizen", "Tizen"):
+ runtime = "native"
+ self.create['runtime'] = runtime
+
+configmgr = ConfigMgr()
--- /dev/null
+#!/usr/bin/env python\r
+# vim: ai ts=4 sts=4 et sw=4\r
+#\r
+# Copyright (c) 2011 Intel, Inc.\r
+#\r
+# This program is free software; you can redistribute it and/or modify it\r
+# under the terms of the GNU General Public License as published by the Free\r
+# Software Foundation; version 2 of the License\r
+#\r
+# This program is distributed in the hope that it will be useful, but\r
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\r
+# for more details.\r
+#\r
+# You should have received a copy of the GNU General Public License along\r
+# with this program; if not, write to the Free Software Foundation, Inc., 59\r
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
+\r
+"""Local additions to commandline parsing."""\r
+\r
+import os\r
+import re\r
+import functools\r
+\r
+from argparse import RawDescriptionHelpFormatter, ArgumentTypeError\r
+\r
+class MICHelpFormatter(RawDescriptionHelpFormatter):\r
+ """Changed default argparse help output by request from cmdln lovers."""\r
+\r
+ def __init__(self, *args, **kwargs):\r
+ super(MICHelpFormatter, self).__init__(*args, **kwargs)\r
+ self._aliases = {}\r
+\r
+ def add_argument(self, action):\r
+ """Collect aliases."""\r
+\r
+ if action.choices:\r
+ for item, parser in action.choices.iteritems():\r
+ self._aliases[str(item)] = parser.get_default('alias')\r
+\r
+ return super(MICHelpFormatter, self).add_argument(action)\r
+\r
+ def format_help(self):\r
+ """\r
+ There is no safe and documented way in argparse to reformat\r
+ help output through APIs as almost all of them are private,\r
+ so this method just parses the output and changes it.\r
+ """\r
+ result = []\r
+ subcomm = False\r
+ for line in super(MICHelpFormatter, self).format_help().split('\n'):\r
+ if line.strip().startswith('{'):\r
+ continue\r
+ if line.startswith('optional arguments:'):\r
+ line = 'Global Options:'\r
+ if line.startswith('usage:'):\r
+ line = "Usage: mic [GLOBAL-OPTS] SUBCOMMAND [OPTS]"\r
+ if subcomm:\r
+ match = re.match("[ ]+([^ ]+)[ ]+(.+)", line)\r
+ if match:\r
+ name, help_text = match.group(1), match.group(2)\r
+ alias = self._aliases.get(name) or ''\r
+ if alias:\r
+ alias = "(%s)" % alias\r
+ line = " %-22s%s" % ("%s %s" % (name, alias), help_text)\r
+ if line.strip().startswith('subcommands:'):\r
+ line = 'Subcommands:'\r
+ subcomm = True\r
+ result.append(line)\r
+ return '\n'.join(result)\r
+\r
+def subparser(func):\r
+ """Convenient decorator for subparsers."""\r
+ @functools.wraps(func)\r
+ def wrapper(parser):\r
+ """\r
+ Create subparser\r
+ Set first line of function's docstring as a help\r
+ and the rest of the lines as a description.\r
+ Set attribute 'module' of subparser to 'cmd'+first part of function name\r
+ """\r
+ splitted = func.__doc__.split('\n')\r
+ name = func.__name__.split('_')[0]\r
+ subpar = parser.add_parser(name, help=splitted[0],\r
+ description='\n'.join(splitted[1:]),\r
+ formatter_class=RawDescriptionHelpFormatter)\r
+ subpar.set_defaults(module="cmd_%s" % name)\r
+ return func(subpar)\r
+ return wrapper\r
+\r
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2007 Red Hat Inc.
+# Copyright (c) 2009, 2010, 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+from __future__ import with_statement
+import os, sys
+import stat
+import tempfile
+import shutil
+import subprocess
+import re
+import tarfile
+import glob
+import json
+import errno
+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, 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
+
+class BaseImageCreator(object):
+ """Installs a system to a chroot directory.
+
+ ImageCreator is the simplest creator class available; it will install and
+ configure a system image according to the supplied kickstart file.
+
+ e.g.
+
+ import mic.imgcreate as imgcreate
+ ks = imgcreate.read_kickstart("foo.ks")
+ imgcreate.ImageCreator(ks, "foo").create()
+
+ """
+ # Output image format
+ img_format = ''
+
+ def __del__(self):
+ self.cleanup()
+
+ def __init__(self, createopts = None, pkgmgr = None):
+ """Initialize an ImageCreator instance.
+
+ ks -- a pykickstart.KickstartParser instance; this instance will be
+ used to drive the install by e.g. providing the list of packages
+ to be installed, the system configuration and %post scripts
+
+ name -- a name for the image; used for e.g. image filenames or
+ filesystem labels
+ """
+
+ self.pkgmgr = pkgmgr
+ self.distro_name = ""
+
+ self.__builddir = None
+ self.__bindmounts = []
+
+ self.ks = None
+ self.name = "target"
+ self.tmpdir = "/var/tmp/mic"
+ self.cachedir = "/var/tmp/mic/cache"
+ self.workdir = "/var/tmp/mic/build"
+ self.destdir = "."
+ self.installerfw_prefix = "INSTALLERFW_"
+ self.target_arch = "noarch"
+ self.strict_mode = False
+ self._local_pkgs_path = None
+ self.pack_to = None
+ self.repourl = {}
+ self.multiple_partitions = False
+ self._imgdir = None
+
+ # If the kernel is save to the destdir when copy_kernel cmd is called.
+ self._need_copy_kernel = False
+ # setup tmpfs tmpdir when enabletmpfs is True
+ self.enabletmpfs = False
+
+ if createopts:
+ # Mapping table for variables that have different names.
+ optmap = {"pkgmgr" : "pkgmgr_name",
+ "arch" : "target_arch",
+ "local_pkgs_path" : "_local_pkgs_path",
+ "copy_kernel" : "_need_copy_kernel",
+ "strict_mode" : "strict_mode",
+ }
+
+ # update setting from createopts
+ for key in createopts.keys():
+ if key in optmap:
+ option = optmap[key]
+ else:
+ option = key
+ setattr(self, option, createopts[key])
+
+ self.destdir = os.path.abspath(os.path.expanduser(self.destdir))
+
+ if self.pack_to:
+ (tar, ext) = os.path.splitext(self.pack_to)
+ if ext in (".gz", ".bz2", ".lzo", ".bz") and tar.endswith(".tar"):
+ ext = ".tar" + ext
+ if ext not in get_archive_suffixes():
+ self.pack_to += ".tar"
+
+ self._dep_checks = ["ls", "bash", "cp", "echo", "modprobe"]
+
+ # Output image file names
+ self.outimage = []
+ # Output info related with manifest
+ self.image_files = {}
+ # A flag to generate checksum
+ self._genchecksum = False
+
+ self._alt_initrd_name = None
+
+ self._recording_pkgs = []
+
+ # available size in root fs, init to 0
+ self._root_fs_avail = 0
+
+ # Name of the disk image file that is created.
+ self._img_name = None
+
+ self.image_format = 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
+
+ if self.target_arch:
+ if self.target_arch.startswith("arm"):
+ for dep in self._dep_checks:
+ if dep == "extlinux":
+ self._dep_checks.remove(dep)
+
+ if not os.path.exists("/usr/bin/qemu-arm") or \
+ not misc.is_statically_linked("/usr/bin/qemu-arm"):
+ self._dep_checks.append("qemu-arm-static")
+
+ if os.path.exists("/proc/sys/vm/vdso_enabled"):
+ vdso_fh = open("/proc/sys/vm/vdso_enabled","r")
+ vdso_value = vdso_fh.read().strip()
+ vdso_fh.close()
+ if (int)(vdso_value) == 1:
+ msger.warning("vdso is enabled on your host, which might "
+ "cause problems with arm emulations.\n"
+ "\tYou can disable vdso with following command before "
+ "starting image build:\n"
+ "\techo 0 | sudo tee /proc/sys/vm/vdso_enabled")
+ elif self.target_arch == "mipsel":
+ for dep in self._dep_checks:
+ if dep == "extlinux":
+ self._dep_checks.remove(dep)
+
+ if not os.path.exists("/usr/bin/qemu-mipsel") or \
+ not misc.is_statically_linked("/usr/bin/qemu-mipsel"):
+ self._dep_checks.append("qemu-mipsel-static")
+
+ if os.path.exists("/proc/sys/vm/vdso_enabled"):
+ vdso_fh = open("/proc/sys/vm/vdso_enabled","r")
+ vdso_value = vdso_fh.read().strip()
+ vdso_fh.close()
+ if (int)(vdso_value) == 1:
+ msger.warning("vdso is enabled on your host, which might "
+ "cause problems with mipsel emulations.\n"
+ "\tYou can disable vdso with following command before "
+ "starting image build:\n"
+ "\techo 0 | sudo tee /proc/sys/vm/vdso_enabled")
+ elif self.target_arch == "riscv64":
+ for dep in self._dep_checks:
+ if dep == "extlinux":
+ self._dep_checks.remove(dep)
+
+ if not os.path.exists("/usr/bin/qemu-riscv64") or \
+ not misc.is_statically_linked("/usr/bin/qemu-riscv64"):
+ self._dep_checks.append("qemu-riscv64-static")
+
+ if os.path.exists("/proc/sys/vm/vdso_enabled"):
+ vdso_fh = open("/proc/sys/vm/vdso_enabled","r")
+ vdso_value = vdso_fh.read().strip()
+ vdso_fh.close()
+ if (int)(vdso_value) == 1:
+ msger.warning("vdso is enabled on your host, which might "
+ "cause problems with riscv64 emulations.\n"
+ "\tYou can disable vdso with following command before "
+ "starting image build:\n"
+ "\techo 0 | sudo tee /proc/sys/vm/vdso_enabled")
+
+ # make sure the specified tmpdir and cachedir exist
+ if not os.path.exists(self.tmpdir):
+ os.makedirs(self.tmpdir)
+ if not os.path.exists(self.cachedir):
+ os.makedirs(self.cachedir)
+
+
+ #
+ # Properties
+ #
+ def __get_instroot(self):
+ if self.__builddir is None:
+ raise CreatorError("_instroot is not valid before calling mount()")
+ return self.__builddir + "/install_root"
+ _instroot = property(__get_instroot)
+ """The location of the install root directory.
+
+ This is the directory into which the system is installed. Subclasses may
+ mount a filesystem image here or copy files to/from here.
+
+ Note, this directory does not exist before ImageCreator.mount() is called.
+
+ Note also, this is a read-only attribute.
+
+ """
+
+ def __get_outdir(self):
+ if self.__builddir is None:
+ raise CreatorError("_outdir is not valid before calling mount()")
+ return self.__builddir + "/out"
+ _outdir = property(__get_outdir)
+ """The staging location for the final image.
+
+ This is where subclasses should stage any files that are part of the final
+ image. ImageCreator.package() will copy any files found here into the
+ requested destination directory.
+
+ Note, this directory does not exist before ImageCreator.mount() is called.
+
+ Note also, this is a read-only attribute.
+
+ """
+
+
+ #
+ # Hooks for subclasses
+ #
+ def _mount_instroot(self, base_on = None):
+ """Mount or prepare the install root directory.
+
+ This is the hook where subclasses may prepare the install root by e.g.
+ mounting creating and loopback mounting a filesystem image to
+ _instroot.
+
+ There is no default implementation.
+
+ base_on -- this is the value passed to mount() and can be interpreted
+ as the subclass wishes; it might e.g. be the location of
+ a previously created ISO containing a system image.
+
+ """
+ pass
+
+ def _unmount_instroot(self):
+ """Undo anything performed in _mount_instroot().
+
+ This is the hook where subclasses must undo anything which was done
+ in _mount_instroot(). For example, if a filesystem image was mounted
+ onto _instroot, it should be unmounted here.
+
+ There is no default implementation.
+
+ """
+ pass
+
+ def _create_bootconfig(self):
+ """Configure the image so that it's bootable.
+
+ This is the hook where subclasses may prepare the image for booting by
+ e.g. creating an initramfs and bootloader configuration.
+
+ This hook is called while the install root is still mounted, after the
+ packages have been installed and the kickstart configuration has been
+ applied, but before the %post scripts have been executed.
+
+ There is no default implementation.
+
+ """
+ pass
+
+ def _stage_final_image(self):
+ """Stage the final system image in _outdir.
+
+ This is the hook where subclasses should place the image in _outdir
+ so that package() can copy it to the requested destination directory.
+
+ By default, this moves the install root into _outdir.
+
+ """
+ shutil.move(self._instroot, self._outdir + "/" + self.name)
+
+ def get_installed_packages(self):
+ return self._pkgs_content.keys()
+
+ def _save_recording_pkgs(self, destdir):
+ """Save the list or content of installed packages to file.
+ """
+ pkgs = self._pkgs_content.keys()
+ pkgs.sort() # inplace op
+
+ if not os.path.exists(destdir):
+ os.makedirs(destdir)
+
+ content = None
+ if 'vcs' in self._recording_pkgs:
+ vcslst = ["%s %s" % (k, v) for (k, v) in self._pkgs_vcsinfo.items()]
+ content = '\n'.join(sorted(vcslst))
+ elif 'name' in self._recording_pkgs:
+ content = '\n'.join(pkgs)
+ if content:
+ namefile = os.path.join(destdir, self.name + '.packages')
+ f = open(namefile, "w")
+ f.write(content)
+ f.close()
+ self.outimage.append(namefile)
+
+ # if 'content', save more details
+ if 'content' in self._recording_pkgs:
+ contfile = os.path.join(destdir, self.name + '.files')
+ f = open(contfile, "w")
+
+ for pkg in pkgs:
+ content = pkg + '\n'
+
+ pkgcont = self._pkgs_content[pkg]
+ content += ' '
+ content += '\n '.join(pkgcont)
+ content += '\n'
+
+ content += '\n'
+ f.write(content)
+ f.close()
+ self.outimage.append(contfile)
+
+ if 'license' in self._recording_pkgs:
+ licensefile = os.path.join(destdir, self.name + '.license')
+ f = open(licensefile, "w")
+
+ f.write('Summary:\n')
+ for license in reversed(sorted(self._pkgs_license, key=\
+ lambda license: len(self._pkgs_license[license]))):
+ f.write(" - %s: %s\n" \
+ % (license, len(self._pkgs_license[license])))
+
+ f.write('\nDetails:\n')
+ for license in reversed(sorted(self._pkgs_license, key=\
+ lambda license: len(self._pkgs_license[license]))):
+ f.write(" - %s:\n" % (license))
+ for pkg in sorted(self._pkgs_license[license]):
+ f.write(" - %s\n" % (pkg))
+ f.write('\n')
+
+ f.close()
+ self.outimage.append(licensefile)
+
+ def _get_required_packages(self):
+ """Return a list of required packages.
+
+ This is the hook where subclasses may specify a set of packages which
+ it requires to be installed.
+
+ This returns an empty list by default.
+
+ Note, subclasses should usually chain up to the base class
+ implementation of this hook.
+
+ """
+ return []
+
+ def _get_excluded_packages(self):
+ """Return a list of excluded packages.
+
+ This is the hook where subclasses may specify a set of packages which
+ it requires _not_ to be installed.
+
+ This returns an empty list by default.
+
+ Note, subclasses should usually chain up to the base class
+ implementation of this hook.
+
+ """
+ return []
+
+ 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.
+
+ """
+ if self._local_pkgs_path:
+ if os.path.isdir(self._local_pkgs_path):
+ return glob.glob(
+ os.path.join(self._local_pkgs_path, '*.rpm'))
+ elif os.path.splitext(self._local_pkgs_path)[-1] == '.rpm':
+ return [self._local_pkgs_path]
+
+ return []
+
+ def _get_fstab(self):
+ """Return the desired contents of /etc/fstab.
+
+ This is the hook where subclasses may specify the contents of
+ /etc/fstab by returning a string containing the desired contents.
+
+ A sensible default implementation is provided.
+
+ """
+ s = "/dev/root / %s %s 0 0\n" \
+ % (self._fstype,
+ "defaults,noatime" if not self._fsopts else self._fsopts)
+ s += self._get_fstab_special()
+ return s
+
+ def _get_fstab_special(self):
+ s = "devpts /dev/pts devpts gid=5,mode=620 0 0\n"
+ s += "tmpfs /dev/shm tmpfs defaults 0 0\n"
+ s += "proc /proc proc defaults 0 0\n"
+ s += "sysfs /sys sysfs defaults 0 0\n"
+ return s
+
+ def _set_part_env(self, pnum, prop, value):
+ """ This is a helper function which generates an environment variable
+ for a property "prop" with value "value" of a partition number "pnum".
+
+ The naming convention is:
+ * Variables start with INSTALLERFW_PART
+ * Then goes the partition number, the order is the same as
+ specified in the KS file
+ * Then goes the property name
+ """
+
+ if value == None:
+ value = ""
+ else:
+ value = str(value)
+
+ name = self.installerfw_prefix + ("PART%d_" % pnum) + prop
+ return { name : value }
+
+ def _get_post_scripts_env(self, in_chroot):
+ """Return an environment dict for %post scripts.
+
+ This is the hook where subclasses may specify some environment
+ variables for %post scripts by return a dict containing the desired
+ environment.
+
+ in_chroot -- whether this %post script is to be executed chroot()ed
+ into _instroot.
+ """
+
+ env = {}
+ pnum = 0
+
+ for p in kickstart.get_partitions(self.ks):
+ env.update(self._set_part_env(pnum, "SIZE", p.size))
+ env.update(self._set_part_env(pnum, "MOUNTPOINT", p.mountpoint))
+ env.update(self._set_part_env(pnum, "FSTYPE", p.fstype))
+ env.update(self._set_part_env(pnum, "LABEL", p.label))
+ env.update(self._set_part_env(pnum, "FSOPTS", p.fsopts))
+ env.update(self._set_part_env(pnum, "BOOTFLAG", p.active))
+ env.update(self._set_part_env(pnum, "ALIGN", p.align))
+ env.update(self._set_part_env(pnum, "TYPE_ID", p.part_type))
+ env.update(self._set_part_env(pnum, "UUID", p.uuid))
+ env.update(self._set_part_env(pnum, "DEVNODE",
+ "/dev/%s%d" % (p.disk, pnum + 1)))
+ env.update(self._set_part_env(pnum, "DISK_DEVNODE",
+ "/dev/%s" % p.disk))
+ pnum += 1
+
+ # Count of paritions
+ env[self.installerfw_prefix + "PART_COUNT"] = str(pnum)
+
+ # Partition table format
+ ptable_format = self.ks.handler.bootloader.ptable
+ env[self.installerfw_prefix + "PTABLE_FORMAT"] = ptable_format
+
+ # The kerned boot parameters
+ kernel_opts = self.ks.handler.bootloader.appendLine
+ env[self.installerfw_prefix + "KERNEL_OPTS"] = kernel_opts
+
+ # Name of the image creation tool
+ env[self.installerfw_prefix + "INSTALLER_NAME"] = "mic"
+
+ # The real current location of the mounted file-systems
+ if in_chroot:
+ mount_prefix = "/"
+ else:
+ mount_prefix = self._instroot
+ env[self.installerfw_prefix + "MOUNT_PREFIX"] = mount_prefix
+
+ # These are historical variables which lack the common name prefix
+ 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
+
+ def __get_imgname(self):
+ return self.name
+ _name = property(__get_imgname)
+ """The name of the image file.
+
+ """
+
+ def _get_kernel_versions(self):
+ """Return a dict detailing the available kernel types/versions.
+
+ This is the hook where subclasses may override what kernel types and
+ versions should be available for e.g. creating the booloader
+ configuration.
+
+ A dict should be returned mapping the available kernel types to a list
+ of the available versions for those kernels.
+
+ The default implementation uses rpm to iterate over everything
+ providing 'kernel', finds /boot/vmlinuz-* and returns the version
+ obtained from the vmlinuz filename. (This can differ from the kernel
+ RPM's n-v-r in the case of e.g. xen)
+
+ """
+ def get_kernel_versions(instroot):
+ ret = {}
+ versions = set()
+ files = glob.glob(instroot + "/boot/vmlinuz-*")
+ for file in files:
+ version = os.path.basename(file)[8:]
+ if version is None:
+ continue
+ versions.add(version)
+ ret["kernel"] = list(versions)
+ return ret
+
+ def get_version(header):
+ version = None
+ for f in header['filenames']:
+ if f.startswith('/boot/vmlinuz-'):
+ version = f[14:]
+ return version
+
+ if self.ks is None:
+ return get_kernel_versions(self._instroot)
+
+ ts = rpm.TransactionSet(self._instroot)
+
+ ret = {}
+ for header in ts.dbMatch('provides', 'kernel'):
+ version = get_version(header)
+ if version is None:
+ continue
+
+ name = header['name']
+ if not name in ret:
+ ret[name] = [version]
+ elif not version in ret[name]:
+ ret[name].append(version)
+
+ return ret
+
+
+ #
+ # Helpers for subclasses
+ #
+ def _do_bindmounts(self):
+ """Mount various system directories onto _instroot.
+
+ This method is called by mount(), but may also be used by subclasses
+ in order to re-mount the bindmounts after modifying the underlying
+ filesystem.
+
+ """
+ for b in self.__bindmounts:
+ b.mount()
+
+ def _undo_bindmounts(self):
+ """Unmount the bind-mounted system directories from _instroot.
+
+ This method is usually only called by unmount(), but may also be used
+ by subclasses in order to gain access to the filesystem obscured by
+ the bindmounts - e.g. in order to create device nodes on the image
+ filesystem.
+
+ """
+ self.__bindmounts.reverse()
+ for b in self.__bindmounts:
+ b.unmount()
+
+ def _chroot(self):
+ """Chroot into the install root.
+
+ This method may be used by subclasses when executing programs inside
+ the install root e.g.
+
+ subprocess.call(["/bin/ls"], preexec_fn = self.chroot)
+
+ """
+ os.chroot(self._instroot)
+ os.chdir("/")
+
+ def _mkdtemp(self, prefix = "tmp-"):
+ """Create a temporary directory.
+
+ This method may be used by subclasses to create a temporary directory
+ for use in building the final image - e.g. a subclass might create
+ a temporary directory in order to bundle a set of files into a package.
+
+ The subclass may delete this directory if it wishes, but it will be
+ automatically deleted by cleanup().
+
+ The absolute path to the temporary directory is returned.
+
+ Note, this method should only be called after mount() has been called.
+
+ prefix -- a prefix which should be used when creating the directory;
+ defaults to "tmp-".
+
+ """
+ self.__ensure_builddir()
+ return tempfile.mkdtemp(dir = self.__builddir, prefix = prefix)
+
+ def _mkstemp(self, prefix = "tmp-"):
+ """Create a temporary file.
+
+ This method may be used by subclasses to create a temporary file
+ for use in building the final image - e.g. a subclass might need
+ a temporary location to unpack a compressed file.
+
+ The subclass may delete this file if it wishes, but it will be
+ automatically deleted by cleanup().
+
+ A tuple containing a file descriptor (returned from os.open() and the
+ absolute path to the temporary directory is returned.
+
+ Note, this method should only be called after mount() has been called.
+
+ prefix -- a prefix which should be used when creating the file;
+ defaults to "tmp-".
+
+ """
+ self.__ensure_builddir()
+ return tempfile.mkstemp(dir = self.__builddir, prefix = prefix)
+
+ def _mktemp(self, prefix = "tmp-"):
+ """Create a temporary file.
+
+ This method simply calls _mkstemp() and closes the returned file
+ descriptor.
+
+ The absolute path to the temporary file is returned.
+
+ Note, this method should only be called after mount() has been called.
+
+ prefix -- a prefix which should be used when creating the file;
+ defaults to "tmp-".
+
+ """
+
+ (f, path) = self._mkstemp(prefix)
+ os.close(f)
+ return path
+
+
+ #
+ # Actual implementation
+ #
+ def __ensure_builddir(self):
+ if not self.__builddir is None:
+ return
+
+ try:
+ self.workdir = os.path.join(self.tmpdir, "build")
+ if not os.path.exists(self.workdir):
+ os.makedirs(self.workdir)
+ self.__builddir = tempfile.mkdtemp(dir = self.workdir,
+ prefix = "imgcreate-")
+ except OSError as msg:
+ raise CreatorError("Failed create build directory in %s: %s" %
+ (self.tmpdir, msg))
+
+ def get_cachedir(self, cachedir = None):
+ if self.cachedir:
+ return self.cachedir
+
+ self.__ensure_builddir()
+ if cachedir:
+ self.cachedir = cachedir
+ else:
+ self.cachedir = self.__builddir + "/mic-cache"
+ fs.makedirs(self.cachedir)
+ return self.cachedir
+
+ def __sanity_check(self):
+ """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")
+
+ kickstart.convert_method_to_repo(self.ks)
+
+ if not kickstart.get_repos(self.ks):
+ raise CreatorError("No repositories specified")
+
+ def __write_fstab(self):
+ if kickstart.use_installerfw(self.ks, "fstab"):
+ # The fstab file will be generated by installer framework scripts
+ # instead.
+ return None
+ fstab_contents = self._get_fstab()
+ if fstab_contents:
+ fstab = open(self._instroot + "/etc/fstab", "w")
+ fstab.write(fstab_contents)
+ fstab.close()
+
+ def __create_minimal_dev(self):
+ """Create a minimal /dev so that we don't corrupt the host /dev"""
+ origumask = os.umask(0000)
+ devices = (('null', 1, 3, 0o666),
+ ('urandom',1, 9, 0o666),
+ ('random', 1, 8, 0o666),
+ ('full', 1, 7, 0o666),
+ ('ptmx', 5, 2, 0o666),
+ ('tty', 5, 0, 0o666),
+ ('zero', 1, 5, 0o666))
+
+ links = (("/proc/self/fd", "/dev/fd"),
+ ("/proc/self/fd/0", "/dev/stdin"),
+ ("/proc/self/fd/1", "/dev/stdout"),
+ ("/proc/self/fd/2", "/dev/stderr"))
+
+ for (node, major, minor, perm) in devices:
+ if not os.path.exists(self._instroot + "/dev/" + node):
+ os.mknod(self._instroot + "/dev/" + node,
+ perm | stat.S_IFCHR,
+ os.makedev(major,minor))
+
+ for (src, dest) in links:
+ if not os.path.exists(self._instroot + dest):
+ os.symlink(src, self._instroot + dest)
+
+ os.umask(origumask)
+
+ def __setup_tmpdir(self):
+ if not self.enabletmpfs:
+ return
+
+ runner.show('mount -t tmpfs -o size=4G tmpfs %s' % self.workdir)
+
+ def __clean_tmpdir(self):
+ if not self.enabletmpfs:
+ return
+
+ 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.
+
+ This function sets up the filesystem which the ImageCreator will
+ install into and configure. The ImageCreator class merely creates an
+ install root directory, bind mounts some system directories (e.g. /dev)
+ and writes out /etc/fstab. Other subclasses may also e.g. create a
+ sparse file, format it and loopback mount it to the install root.
+
+ base_on -- a previous install on which to base this install; defaults
+ to None, causing a new image to be created
+
+ cachedir -- a directory in which to store the Yum cache; defaults to
+ None, causing a new cache to be created; by setting this
+ to another directory, the same cache can be reused across
+ multiple installs.
+
+ """
+ self.__setup_tmpdir()
+ self.__ensure_builddir()
+
+ # prevent popup dialog in Ubuntu(s)
+ misc.hide_loopdev_presentation()
+
+ fs.makedirs(self._instroot)
+ fs.makedirs(self._outdir)
+
+ self._mount_instroot(base_on)
+
+ for d in ("/dev/pts",
+ "/etc",
+ "/boot",
+ "/var/log",
+ "/sys",
+ "/proc",
+ "/usr/bin"):
+ fs.makedirs(self._instroot + d)
+
+ if self.target_arch and self.target_arch.startswith("arm") or \
+ self.target_arch == "aarch64" or self.target_arch == "riscv64":
+ self.qemu_emulators = misc.setup_qemu_emulator(self._instroot,
+ self.target_arch)
+
+ self.get_cachedir(cachedir)
+
+ # bind mount system directories into _instroot
+ for (f, dest) in [("/sys", None),
+ ("/proc", None),
+ ("/proc/sys/fs/binfmt_misc", None),
+ ("/dev/pts", None)]:
+ self.__bindmounts.append(
+ fs.BindChrootMount(
+ f, self._instroot, dest))
+
+ self._do_bindmounts()
+
+ self.__create_minimal_dev()
+
+ if os.path.exists(self._instroot + "/etc/mtab"):
+ os.unlink(self._instroot + "/etc/mtab")
+ os.symlink("../proc/mounts", self._instroot + "/etc/mtab")
+
+ #self.__write_fstab()
+
+ # 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.
+
+ The ImageCreator class detaches the system from the install root, but
+ other subclasses may also detach the loopback mounted filesystem image
+ from the install root.
+
+ """
+ try:
+ mtab = self._instroot + "/etc/mtab"
+ if not os.path.islink(mtab):
+ os.unlink(self._instroot + "/etc/mtab")
+
+ for qemu_emulator in self.qemu_emulators:
+ os.unlink(self._instroot + qemu_emulator)
+ except OSError:
+ pass
+
+ self._undo_bindmounts()
+
+ """ Clean up yum garbage """
+ try:
+ instroot_pdir = os.path.dirname(self._instroot + self._instroot)
+ if os.path.exists(instroot_pdir):
+ shutil.rmtree(instroot_pdir, ignore_errors = True)
+ yumlibdir = self._instroot + "/var/lib/yum"
+ if os.path.exists(yumlibdir):
+ shutil.rmtree(yumlibdir, ignore_errors = True)
+ except OSError:
+ pass
+
+ self._unmount_instroot()
+
+ # reset settings of popup dialog in Ubuntu(s)
+ misc.unhide_loopdev_presentation()
+
+
+ def cleanup(self):
+ """Unmounts the target filesystem and deletes temporary files.
+
+ This method calls unmount() and then deletes any temporary files and
+ directories that were created on the host system while building the
+ image.
+
+ Note, make sure to call this method once finished with the creator
+ instance in order to ensure no stale files are left on the host e.g.:
+
+ creator = ImageCreator(ks, name)
+ try:
+ creator.create()
+ finally:
+ creator.cleanup()
+
+ """
+ if not self.__builddir:
+ return
+
+ kill_proc_inchroot(self._instroot)
+
+ self.unmount()
+
+ shutil.rmtree(self.__builddir, ignore_errors = True)
+ self.__builddir = None
+
+ self.__clean_tmpdir()
+
+ def __is_excluded_pkg(self, pkg):
+ if pkg in self._excluded_pkgs:
+ self._excluded_pkgs.remove(pkg)
+ return True
+
+ for xpkg in self._excluded_pkgs:
+ if xpkg.endswith('*'):
+ if pkg.startswith(xpkg[:-1]):
+ return True
+ elif xpkg.startswith('*'):
+ if pkg.endswith(xpkg[1:]):
+ return True
+
+ return None
+
+ def __select_packages(self, pkg_manager):
+ skipped_pkgs = []
+ for pkg in self._required_pkgs:
+ e = pkg_manager.selectPackage(pkg)
+ if e:
+ if kickstart.ignore_missing(self.ks):
+ skipped_pkgs.append(pkg)
+ elif self.__is_excluded_pkg(pkg):
+ skipped_pkgs.append(pkg)
+ else:
+ raise CreatorError("Failed to find package '%s' : %s" %
+ (pkg, e))
+
+ for pkg in skipped_pkgs:
+ msger.warning("Skipping missing package '%s'" % (pkg,))
+
+ def __select_groups(self, pkg_manager):
+ skipped_groups = []
+ for group in self._required_groups:
+ e = pkg_manager.selectGroup(group.name, group.include)
+ if e:
+ if kickstart.ignore_missing(self.ks):
+ skipped_groups.append(group)
+ else:
+ raise CreatorError("Failed to find group '%s' : %s" %
+ (group.name, e))
+
+ for group in skipped_groups:
+ msger.warning("Skipping missing group '%s'" % (group.name,))
+
+ def __deselect_packages(self, pkg_manager):
+ for pkg in self._excluded_pkgs:
+ pkg_manager.deselectPackage(pkg)
+
+ """def __localinst_packages(self, pkg_manager):
+ for rpm_path in self._get_local_packages():
+ pkg_manager.installLocal(rpm_path)"""
+
+ def __preinstall_packages(self, pkg_manager):
+ if not self.ks:
+ return
+
+ self._preinstall_pkgs = kickstart.get_pre_packages(self.ks)
+ for pkg in self._preinstall_pkgs:
+ pkg_manager.preInstall(pkg)
+
+ def __check_packages(self, pkg_manager):
+ for pkg in self.check_pkgs:
+ pkg_manager.checkPackage(pkg)
+
+ def __attachment_packages(self, pkg_manager):
+ if not self.ks:
+ return
+
+ self._attachment = []
+ for item in kickstart.get_attachment(self.ks):
+ if item.startswith('/'):
+ fpaths = os.path.join(self._instroot, item.lstrip('/'))
+ for fpath in glob.glob(fpaths):
+ self._attachment.append(fpath)
+ continue
+
+ filelist = pkg_manager.getFilelist(item)
+ if filelist:
+ # found rpm in rootfs
+ for pfile in pkg_manager.getFilelist(item):
+ fpath = os.path.join(self._instroot, pfile.lstrip('/'))
+ self._attachment.append(fpath)
+ continue
+
+ # try to retrieve rpm file
+ (url, proxies) = pkg_manager.package_url(item)
+ if not url:
+ msger.warning("Can't get url from repo for %s" % item)
+ continue
+ fpath = os.path.join(self.cachedir, os.path.basename(url))
+ if not os.path.exists(fpath):
+ # download pkgs
+ try:
+ fpath = grabber.myurlgrab(url.full, fpath, proxies, None)
+ except CreatorError:
+ raise
+
+ tmpdir = self._mkdtemp()
+ misc.extract_rpm(fpath, tmpdir)
+ for (root, dirs, files) in os.walk(tmpdir):
+ for fname in files:
+ fpath = os.path.join(root, fname)
+ self._attachment.append(fpath)
+
+ def install(self, repo_urls=None):
+ """Install packages into the install root.
+
+ This function installs the packages listed in the supplied kickstart
+ into the install root. By default, the packages are installed from the
+ repository URLs specified in the kickstart.
+
+ repo_urls -- a dict which maps a repository name to a repository;
+ if supplied, this causes any repository URLs specified in
+ the kickstart to be overridden.
+
+ """
+ def checkScriptletError(dirname, suffix):
+ if os.path.exists(dirname):
+ list = os.listdir(dirname)
+ for line in list:
+ filepath = os.path.join(dirname, line)
+ if os.path.isfile(filepath) and 0 < line.find(suffix):
+ return True
+ else:
+ continue
+
+ return False
+
+ def showErrorInfo(filepath):
+ if os.path.isfile(filepath):
+ for line in open(filepath):
+ msger.info("The error install package info: %s" % line)
+ else:
+ msger.info("%s is not found." % filepath)
+
+ def get_ssl_verify(ssl_verify=None):
+ if ssl_verify is not None:
+ return not ssl_verify.lower().strip() == 'no'
+ else:
+ return not self.ssl_verify.lower().strip() == 'no'
+
+ # initialize pkg list to install
+ if self.ks:
+ self.__sanity_check()
+
+ self._required_pkgs = \
+ kickstart.get_packages(self.ks, self._get_required_packages())
+ self._excluded_pkgs = \
+ kickstart.get_excluded(self.ks, self._get_excluded_packages())
+ self._required_groups = kickstart.get_groups(self.ks)
+ else:
+ self._required_pkgs = None
+ self._excluded_pkgs = None
+ self._required_groups = None
+
+ if not repo_urls:
+ repo_urls = self.extrarepos
+
+ pkg_manager = self.get_pkg_manager()
+ pkg_manager.setup()
+
+ if hasattr(self, 'install_pkgs') and self.install_pkgs:
+ 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,
+ source, gpgkey, disable, ssl_verify, nocache,
+ cost, priority) = repo
+
+ ssl_verify = get_ssl_verify(ssl_verify)
+ yr = pkg_manager.addRepository(name, baseurl, mirrorlist, proxy,
+ proxy_username, proxy_password, inc, exc, ssl_verify,
+ nocache, cost, priority)
+
+ if kickstart.exclude_docs(self.ks):
+ rpm.addMacro("_excludedocs", "1")
+ rpm.addMacro("_dbpath", "/var/lib/rpm")
+ rpm.addMacro("__file_context_path", "%{nil}")
+ if kickstart.inst_langs(self.ks) != None:
+ rpm.addMacro("_install_langs", kickstart.inst_langs(self.ks))
+
+ try:
+ self.__preinstall_packages(pkg_manager)
+ self.__select_packages(pkg_manager)
+ self.__select_groups(pkg_manager)
+ self.__deselect_packages(pkg_manager)
+ #self.__localinst_packages(pkg_manager)
+ self.__check_packages(pkg_manager)
+
+ BOOT_SAFEGUARD = 256 * 1024 * 1024 # 256M
+ checksize = self._root_fs_avail
+ if checksize:
+ checksize -= BOOT_SAFEGUARD
+ if self.target_arch:
+ pkg_manager._add_prob_flags(rpm.RPMPROB_FILTER_IGNOREARCH)
+
+ # If we have multiple partitions, don't check diskspace when rpm run transaction
+ # because rpm check '/' partition only.
+ if self.multiple_partitions:
+ pkg_manager._add_prob_flags(rpm.RPMPROB_FILTER_DISKSPACE)
+ pkg_manager.runInstall(checksize)
+ except CreatorError as e:
+ raise
+ except KeyboardInterrupt:
+ raise
+ else:
+ self._pkgs_content = pkg_manager.getAllContent()
+ self._pkgs_license = pkg_manager.getPkgsLicense()
+ self._pkgs_vcsinfo = pkg_manager.getVcsInfo()
+ self.__attachment_packages(pkg_manager)
+ finally:
+ pkg_manager.close()
+
+ if checkScriptletError(self._instroot + "/tmp/.postscript/error/", "_error"):
+ showErrorInfo(self._instroot + "/tmp/.preload_install_error")
+ raise CreatorError('scriptlet errors occurred')
+
+ # hook post install
+ self.postinstall()
+
+ # do some clean up to avoid lvm info leakage. this sucks.
+ for subdir in ("cache", "backup", "archive"):
+ lvmdir = self._instroot + "/etc/lvm/" + subdir
+ try:
+ for f in os.listdir(lvmdir):
+ os.unlink(lvmdir + "/" + f)
+ 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", 0o755)
+ 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, 0o700)
+
+ 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 as 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 post scripts ...")
+ if os.path.exists(self._instroot + "/tmp"):
+ shutil.rmtree(self._instroot + "/tmp")
+ os.mkdir (self._instroot + "/tmp", 0o755)
+ for s in kickstart.get_post_scripts(self.ks):
+ (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, 0o700)
+
+ env = self._get_post_scripts_env(s.inChroot)
+ if 'PATH' not in env:
+ env['PATH'] = '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin'
+
+ if not s.inChroot:
+ preexec = None
+ script = path
+ else:
+ preexec = self._chroot
+ script = "/tmp/" + os.path.basename(path)
+ start_time = time.time()
+ try:
+ try:
+ p = subprocess.Popen([s.interp, script],
+ preexec_fn = preexec,
+ env = env,
+ stdout = subprocess.PIPE,
+ stderr = subprocess.STDOUT)
+ while p.poll() == None:
+ msger.info(p.stdout.readline().strip())
+ end_time = time.time()
+ if (end_time - start_time)/60 > configmgr.create['postscripts_maxruntime']:
+ raise CreatorError("Your post script is executed more than %d mins, please check it!" % configmgr.create['postscripts_maxruntime'])
+ if p.returncode != 0:
+ raise CreatorError("Failed to execute %%post script "
+ "with '%s'" % (s.interp))
+ except OSError as msg:
+ raise CreatorError("Failed to execute %%post script "
+ "with '%s' : %s" % (s.interp, msg))
+ finally:
+ os.unlink(path)
+
+ def __save_repo_keys(self, repodata):
+ if not repodata:
+ return None
+
+ gpgkeydir = "/etc/pki/rpm-gpg"
+ fs.makedirs(self._instroot + gpgkeydir)
+ for repo in repodata:
+ if repo["repokey"]:
+ repokey = gpgkeydir + "/RPM-GPG-KEY-%s" % repo["name"]
+ shutil.copy(repo["repokey"], self._instroot + repokey)
+
+ def configure(self, repodata = None):
+ """Configure the system image according to the kickstart.
+
+ This method applies the (e.g. keyboard or network) configuration
+ specified in the kickstart and executes the kickstart %post scripts.
+
+ If necessary, it also prepares the image to be bootable by e.g.
+ creating an initrd and bootloader configuration.
+
+ """
+ ksh = self.ks.handler
+
+ msger.info('Applying configurations ...')
+ try:
+ kickstart.LanguageConfig(self._instroot).apply(ksh.lang)
+ kickstart.KeyboardConfig(self._instroot).apply(ksh.keyboard)
+ kickstart.TimezoneConfig(self._instroot).apply(ksh.timezone)
+ #kickstart.AuthConfig(self._instroot).apply(ksh.authconfig)
+ kickstart.FirewallConfig(self._instroot).apply(ksh.firewall)
+ 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)
+ kickstart.RPMMacroConfig(self._instroot).apply(self.ks)
+ kickstart.DesktopConfig(self._instroot).apply(ksh.desktop)
+ self.__save_repo_keys(repodata)
+ kickstart.MoblinRepoConfig(self._instroot).apply(ksh.repo, repodata, self.repourl)
+ except:
+ msger.warning("Failed to apply configuration to image")
+ raise
+
+ self._create_bootconfig()
+ self.__run_post_scripts()
+
+ def launch_shell(self, launch):
+ """Launch a shell in the install root.
+
+ This method is launches a bash shell chroot()ed in the install root;
+ this can be useful for debugging.
+
+ """
+ if launch:
+ msger.info("Launching shell. Exit to continue.")
+ subprocess.call(["/bin/bash"], preexec_fn = self._chroot)
+
+ def do_genchecksum(self, image_name):
+ if not self._genchecksum:
+ return
+
+ md5sum = misc.get_md5sum(image_name)
+ with open(image_name + ".md5sum", "w") as f:
+ f.write("%s %s" % (md5sum, os.path.basename(image_name)))
+ self.outimage.append(image_name+".md5sum")
+
+ def remove_exclude_image(self):
+ for item in self._instloops[:]:
+ if item['exclude_image']:
+ msger.info("Removing %s in image." % item['name'])
+ imgfile = os.path.join(self._imgdir, item['name'])
+ try:
+ os.remove(imgfile)
+ except OSError as err:
+ if err.errno == errno.ENOENT:
+ pass
+ self._instloops.remove(item)
+
+ def create_cpio_image(self):
+ for item in self._instloops:
+ if item['cpioopts']:
+ msger.info("Create image by cpio.")
+ tmp_cpio = self.__builddir + "/tmp-cpio"
+ if not os.path.exists(tmp_cpio):
+ os.mkdir(tmp_cpio)
+ tmp_cpio_imgfile = os.path.join(tmp_cpio, item['name'])
+ try:
+ cpiocmd = fs.find_binary_path('cpio')
+ if cpiocmd:
+ oldoutdir = os.getcwd()
+ os.chdir(os.path.join(self._instroot, item['mountpoint'].lstrip('/')))
+ # find . | cpio --create --'format=newc' | gzip > ../ramdisk.img
+ runner.show('find . | cpio --create %s | gzip > %s' % (item['cpioopts'], tmp_cpio_imgfile))
+ os.chdir(oldoutdir)
+ except OSError as 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.
+
+ In its simplest form, this method merely copies the install root to the
+ supplied destination directory; other subclasses may choose to package
+ the image by e.g. creating a bootable ISO containing the image and
+ bootloader configuration.
+
+ destdir -- the directory into which the final image should be moved;
+ this defaults to the current directory.
+
+ """
+ self.remove_exclude_image()
+
+ self._stage_final_image()
+
+ if not os.path.exists(destdir):
+ fs.makedirs(destdir)
+
+ if self._recording_pkgs:
+ self._save_recording_pkgs(destdir)
+
+ # For image formats with two or multiple image files, it will be
+ # better to put them under a directory
+ if self.image_format in ("raw", "vmdk", "vdi", "nand", "mrstnand"):
+ destdir = os.path.join(destdir, "%s-%s" \
+ % (self.name, self.image_format))
+ msger.debug("creating destination dir: %s" % destdir)
+ fs.makedirs(destdir)
+
+ # Ensure all data is flushed to _outdir
+ runner.quiet('sync')
+
+ misc.check_space_pre_cp(self._outdir, destdir)
+ for f in os.listdir(self._outdir):
+ shutil.move(os.path.join(self._outdir, f),
+ os.path.join(destdir, f))
+ self.outimage.append(os.path.join(destdir, f))
+ self.do_genchecksum(os.path.join(destdir, f))
+
+ def print_outimage_info(self):
+ msg = "The new image can be found here:\n"
+ self.outimage.sort()
+ for file in self.outimage:
+ msg += ' %s\n' % os.path.abspath(file)
+
+ msger.info(msg)
+
+ def check_depend_tools(self):
+ for tool in self._dep_checks:
+ fs.find_binary_path(tool)
+
+ def package_output(self, image_format, destdir = ".", package="none"):
+ if not package or package == "none":
+ return
+
+ destdir = os.path.abspath(os.path.expanduser(destdir))
+ (pkg, comp) = os.path.splitext(package)
+ if comp:
+ comp=comp.lstrip(".")
+
+ if pkg == "tar":
+ if comp:
+ dst = "%s/%s-%s.tar.%s" %\
+ (destdir, self.name, image_format, comp)
+ else:
+ dst = "%s/%s-%s.tar" %\
+ (destdir, self.name, image_format)
+
+ msger.info("creating %s" % dst)
+ tar = tarfile.open(dst, "w:" + comp)
+
+ for file in self.outimage:
+ msger.info("adding %s to %s" % (file, dst))
+ tar.add(file,
+ arcname=os.path.join("%s-%s" \
+ % (self.name, image_format),
+ os.path.basename(file)))
+ if os.path.isdir(file):
+ shutil.rmtree(file, ignore_errors = True)
+ else:
+ os.remove(file)
+
+ tar.close()
+
+ '''All the file in outimage has been packaged into tar.* file'''
+ self.outimage = [dst]
+
+ def release_output(self, config, destdir, release):
+ """ Create release directory and files
+ """
+
+ def _rpath(fn):
+ """ release path """
+ return os.path.join(destdir, fn)
+
+ outimages = self.outimage
+
+ # new ks
+ new_kspath = _rpath(self.name+'.ks')
+ with open(config) as fr:
+ with open(new_kspath, "w") as wf:
+ # When building a release we want to make sure the .ks
+ # file generates the same build even when --release not used.
+ wf.write(fr.read().replace("@BUILD_ID@", release))
+ outimages.append(new_kspath)
+
+ # save log file, logfile is only available in creator attrs
+ if hasattr(self, 'releaselog') and self.releaselog:
+ outimages.append(self.logfile)
+
+ # rename iso and usbimg
+ for f in os.listdir(destdir):
+ if f.endswith(".iso"):
+ newf = f[:-4] + '.img'
+ elif f.endswith(".usbimg"):
+ newf = f[:-7] + '.img'
+ else:
+ continue
+ os.rename(_rpath(f), _rpath(newf))
+ outimages.append(_rpath(newf))
+
+ # generate MD5SUMS SHA1SUMS SHA256SUMS
+ def generate_hashsum(hash_name, hash_method):
+ with open(_rpath(hash_name), "w") as wf:
+ for f in os.listdir(destdir):
+ if f.endswith('SUMS'):
+ continue
+
+ if os.path.isdir(os.path.join(destdir, f)):
+ continue
+
+ hash_value = hash_method(_rpath(f))
+ # There needs to be two spaces between the sum and
+ # filepath to match the syntax with md5sum,sha1sum,
+ # sha256sum. This way also *sum -c *SUMS can be used.
+ wf.write("%s %s\n" % (hash_value, f))
+
+ outimages.append("%s/%s" % (destdir, hash_name))
+
+ hash_dict = {
+ 'MD5SUMS' : misc.get_md5sum,
+ 'SHA1SUMS' : misc.get_sha1sum,
+ 'SHA256SUMS' : misc.get_sha256sum
+ }
+
+ for k, v in hash_dict.items():
+ generate_hashsum(k, v)
+
+ # Filter out the nonexist file
+ for fp in outimages[:]:
+ if not os.path.exists("%s" % fp):
+ outimages.remove(fp)
+
+ def copy_kernel(self):
+ """ Copy kernel files to the outimage directory.
+ NOTE: This needs to be called before unmounting the instroot.
+ """
+
+ if not self._need_copy_kernel:
+ return
+
+ if not os.path.exists(self.destdir):
+ os.makedirs(self.destdir)
+
+ for kernel in glob.glob("%s/boot/vmlinuz-*" % self._instroot):
+ kernelfilename = "%s/%s-%s" % (self.destdir,
+ self.name,
+ os.path.basename(kernel))
+ msger.info('copy kernel file %s as %s' % (os.path.basename(kernel),
+ kernelfilename))
+ shutil.copy(kernel, kernelfilename)
+ self.outimage.append(kernelfilename)
+
+ def copy_attachment(self):
+ """ Subclass implement it to handle attachment files
+ NOTE: This needs to be called before unmounting the instroot.
+ """
+ pass
+
+ def get_pkg_manager(self):
+ return self.pkgmgr(target_arch = self.target_arch,
+ instroot = self._instroot,
+ cachedir = self.cachedir,
+ strict_mode = self.strict_mode)
+
+ def create_manifest(self):
+ def get_pack_suffix():
+ return '.' + self.pack_to.split('.', 1)[1]
+
+ if not os.path.exists(self.destdir):
+ os.makedirs(self.destdir)
+
+ now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ manifest_dict = {'version': VERSION,
+ 'created': now}
+ if self.img_format:
+ manifest_dict.update({'format': self.img_format})
+
+ if hasattr(self, 'logfile') and self.logfile:
+ manifest_dict.update({'log_file': self.logfile})
+
+ if self.image_files:
+ if self.pack_to:
+ self.image_files.update({'pack': get_pack_suffix()})
+ manifest_dict.update({self.img_format: self.image_files})
+
+ msger.info('Creating manifest file...')
+ manifest_file_path = os.path.join(self.destdir, 'manifest.json')
+ with open(manifest_file_path, 'w') as fest_file:
+ json.dump(manifest_dict, fest_file, indent=4)
+ self.outimage.append(manifest_file_path)
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+
+from mic import msger
+from mic.utils import runner, misc
+from mic.utils.errors import CreatorError
+from mic.utils.fs_related import find_binary_path
+from mic.imager.baseimager import BaseImageCreator
+
+class FsImageCreator(BaseImageCreator):
+ img_format = 'fs'
+
+ def __init__(self, cfgmgr = None, pkgmgr = None):
+ self.zips = {
+ "tar.bz2" : ""
+ }
+ BaseImageCreator.__init__(self, cfgmgr, pkgmgr)
+ self._fstype = None
+ self._fsopts = None
+ self._include_src = False
+
+ def package(self, destdir = "."):
+
+ ignores = ["/dev/fd",
+ "/dev/stdin",
+ "/dev/stdout",
+ "/dev/stderr",
+ "/etc/mtab"]
+
+ if not os.path.exists(destdir):
+ os.makedirs(destdir)
+
+ if self._recording_pkgs:
+ self._save_recording_pkgs(destdir)
+
+ if not self.pack_to:
+ self.image_files = {'image_files': [self.name]}
+ fsdir = os.path.join(destdir, self.name)
+
+ misc.check_space_pre_cp(self._instroot, destdir)
+ msger.info("Copying %s to %s ..." % (self._instroot, fsdir))
+ runner.show(['cp', "-af", self._instroot, fsdir])
+
+ for exclude in ignores:
+ if os.path.exists(fsdir + exclude):
+ os.unlink(fsdir + exclude)
+
+ self.outimage.append(fsdir)
+
+ else:
+ self.image_files = {'image_files': [self.pack_to]}
+ (tar, comp) = os.path.splitext(self.pack_to)
+ try:
+ tarcreat = {'.tar': '-cf',
+ '.gz': '-czf',
+ '.bz2': '-cjf',
+ '.tgz': '-czf',
+ '.tbz': '-cjf'}[comp]
+ except KeyError:
+ raise CreatorError("Unsupported comression for this image type:"
+ " '%s', try '.tar', '.tar.gz', etc" % comp)
+
+ dst = os.path.join(destdir, self.pack_to)
+ msger.info("Pack rootfs to %s. Please wait..." % dst)
+
+ tar = find_binary_path('tar')
+ tar_cmdline = [tar, "--numeric-owner",
+ "--preserve-permissions",
+ "--one-file-system",
+ "--directory",
+ self._instroot]
+ for ignore_entry in ignores:
+ if ignore_entry.startswith('/'):
+ ignore_entry = ignore_entry[1:]
+
+ tar_cmdline.append("--exclude=%s" % (ignore_entry))
+
+ tar_cmdline.extend([tarcreat, dst, "."])
+
+ rc = runner.show(tar_cmdline)
+ if rc:
+ raise CreatorError("Failed compress image with tar.bz2. "
+ "Cmdline: %s" % (" ".join(tar_cmdline)))
+
+ self.outimage.append(dst)
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+import sys
+import glob
+import shutil
+
+from mic import kickstart, msger
+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
+
+
+# The maximum string length supported for LoopImageCreator.fslabel
+FSLABEL_MAXLEN = 32
+# Support for Read-only file system list
+AFTER_MNT_FS = {"squashfs":".sqsh", "vdfs":".vdfs"}
+
+def save_mountpoints(fpath, loops, arch = None):
+ """Save mount points mapping to file
+
+ :fpath, the xml file to store partition info
+ :loops, dict of partition info
+ :arch, image arch
+ """
+
+ if not fpath or not loops:
+ return
+
+ from xml.dom import minidom
+ doc = minidom.Document()
+ imgroot = doc.createElement("image")
+ doc.appendChild(imgroot)
+ if arch:
+ imgroot.setAttribute('arch', arch)
+ for loop in loops:
+ part = doc.createElement("partition")
+ imgroot.appendChild(part)
+ for (key, val) in loop.items():
+ if isinstance(val, fs.Mount):
+ continue
+ part.setAttribute(key, str(val))
+
+ with open(fpath, 'w') as wf:
+ wf.write(doc.toprettyxml(indent=' '))
+
+ return
+
+def load_mountpoints(fpath):
+ """Load mount points mapping from file
+
+ :fpath, file path to load
+ """
+
+ if not fpath:
+ return
+
+ from xml.dom import minidom
+ mount_maps = []
+ with open(fpath, 'r') as rf:
+ dom = minidom.parse(rf)
+ imgroot = dom.documentElement
+ for part in imgroot.getElementsByTagName("partition"):
+ p = dict(part.attributes.items())
+
+ try:
+ mp = (p['mountpoint'], p['label'], p['name'],
+ int(p['size']), p['fstype'])
+ except KeyError:
+ msger.warning("Wrong format line in file: %s" % fpath)
+ except ValueError:
+ msger.warning("Invalid size '%s' in file: %s" % (p['size'], fpath))
+ else:
+ mount_maps.append(mp)
+
+ return mount_maps
+
+class LoopImageCreator(BaseImageCreator):
+ """Installs a system into a loopback-mountable filesystem image.
+
+ LoopImageCreator is a straightforward ImageCreator subclass; the system
+ is installed into an ext3 filesystem on a sparse file which can be
+ subsequently loopback-mounted.
+
+ When specifying multiple partitions in kickstart file, each partition
+ will be created as a separated loop image.
+ """
+ img_format = 'loop'
+
+ def __init__(self, creatoropts=None, pkgmgr=None,
+ compress_image=None,
+ shrink_image=False):
+ """Initialize a LoopImageCreator instance.
+
+ This method takes the same arguments as ImageCreator.__init__()
+ with the addition of:
+
+ fslabel -- A string used as a label for any filesystems created.
+ """
+
+ BaseImageCreator.__init__(self, creatoropts, pkgmgr)
+
+ self.compress_image = compress_image
+ self.shrink_image = shrink_image
+
+ self.__fslabel = None
+ self.fslabel = self.name
+
+ self.__blocksize = 4096
+ if self.ks:
+ self.__fstype = kickstart.get_image_fstype(self.ks,
+ "ext3")
+ self.__fsopts = kickstart.get_image_fsopts(self.ks,
+ "defaults,noatime")
+ if self.__fstype in AFTER_MNT_FS.keys():
+ self.__fstype = "ext4"
+
+ allloops = []
+ for part in sorted(kickstart.get_partitions(self.ks),
+ key=lambda p: p.mountpoint):
+ aft_fstype = None
+ if part.fstype == "swap":
+ continue
+ elif part.fstype in AFTER_MNT_FS.keys():
+ aft_fstype = part.fstype
+ part.fstype = "ext4"
+
+ label = part.label
+ fslabel = part.fslabel
+ if fslabel == '':
+ fslabel = label
+ mp = part.mountpoint
+ if mp == '/':
+ # the base image
+ if not label:
+ label = self.name
+ else:
+ mp = mp.rstrip('/')
+ if not label:
+ msger.warning('no "label" specified for loop img at %s'
+ ', use the mountpoint as the name' % mp)
+ label = mp.split('/')[-1]
+
+ imgname = misc.strip_end(label, '.img') + '.img'
+ allloops.append({
+ 'mountpoint': mp,
+ 'label': label,
+ 'fslabel':fslabel,
+ 'name': imgname,
+ 'size': part.size or 4096 * 1024 * 1024,
+ 'fstype': part.fstype or 'ext3',
+ 'fsopts': part.fsopts or None,
+ 'aft_fstype': aft_fstype or None,
+ 'extopts': part.extopts or None,
+ 'f2fsopts': part.f2fsopts or None,
+ 'vdfsopts': part.vdfsopts or None,
+ 'squashfsopts': part.squashfsopts or None,
+ 'squashfsoptions_maxsize': part.squashfsoptions_maxsize 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
+
+ else:
+ self.__fstype = None
+ self.__fsopts = None
+ self._instloops = []
+
+ self._imgdir = None
+ self._umountdir = None
+
+ if self.ks:
+ self.__image_size = kickstart.get_image_size(self.ks,
+ 4096 * 1024 * 1024)
+ else:
+ self.__image_size = 0
+
+ self._img_name = self.name + ".img"
+
+ def get_image_names(self):
+ if not self._instloops:
+ return None
+
+ names = []
+ for lo in self._instloops :
+ names.append(lo['name'])
+ for ro in AFTER_MNT_FS.values():
+ names.append(lo['name'].replace('.img',ro))
+ return list(set(names))
+
+ def _set_fstype(self, fstype):
+ self.__fstype = fstype
+
+ def _set_image_size(self, imgsize):
+ self.__image_size = imgsize
+
+
+ #
+ # Properties
+ #
+ def __get_fslabel(self):
+ if self.__fslabel is None:
+ return self.name
+ else:
+ return self.__fslabel
+ def __set_fslabel(self, val):
+ if val is None:
+ self.__fslabel = None
+ else:
+ self.__fslabel = val[:FSLABEL_MAXLEN]
+ #A string used to label any filesystems created.
+ #
+ #Some filesystems impose a constraint on the maximum allowed size of the
+ #filesystem label. In the case of ext3 it's 16 characters, but in the case
+ #of ISO9660 it's 32 characters.
+ #
+ #mke2fs silently truncates the label, but mkisofs aborts if the label is
+ #too long. So, for convenience sake, any string assigned to this attribute
+ #is silently truncated to FSLABEL_MAXLEN (32) characters.
+ fslabel = property(__get_fslabel, __set_fslabel)
+
+ def __get_image(self):
+ if self._imgdir is None:
+ raise CreatorError("_image is not valid before calling mount()")
+ return os.path.join(self._imgdir, self._img_name)
+ #The location of the image file.
+ #
+ #This is the path to the filesystem image. Subclasses may use this path
+ #in order to package the image in _stage_final_image().
+ #
+ #Note, this directory does not exist before ImageCreator.mount() is called.
+ #
+ #Note also, this is a read-only attribute.
+ _image = property(__get_image)
+
+ def __get_blocksize(self):
+ return self.__blocksize
+ def __set_blocksize(self, val):
+ if self._instloops:
+ raise CreatorError("_blocksize must be set before calling mount()")
+ try:
+ self.__blocksize = int(val)
+ except ValueError:
+ raise CreatorError("'%s' is not a valid integer value "
+ "for _blocksize" % val)
+ #The block size used by the image's filesystem.
+ #
+ #This is the block size used when creating the filesystem image. Subclasses
+ #may change this if they wish to use something other than a 4k block size.
+ #
+ #Note, this attribute may only be set before calling mount().
+ _blocksize = property(__get_blocksize, __set_blocksize)
+
+ def __get_fstype(self):
+ return self.__fstype
+ def __set_fstype(self, val):
+ if val != "ext2" and val != "ext3":
+ raise CreatorError("Unknown _fstype '%s' supplied" % val)
+ self.__fstype = val
+ #The type of filesystem used for the image.
+ #
+ #This is the filesystem type used when creating the filesystem image.
+ #Subclasses may change this if they wish to use something other ext3.
+ #
+ #Note, only ext2 and ext3 are currently supported.
+ #
+ #Note also, this attribute may only be set before calling mount().
+ _fstype = property(__get_fstype, __set_fstype)
+
+ def __get_fsopts(self):
+ return self.__fsopts
+ def __set_fsopts(self, val):
+ self.__fsopts = val
+ #Mount options of filesystem used for the image.
+ #
+ #This can be specified by --fsoptions="xxx,yyy" in part command in
+ #kickstart file.
+ _fsopts = property(__get_fsopts, __set_fsopts)
+
+
+ #
+ # Helpers for subclasses
+ #
+ def _resparse(self, size=None):
+ """Rebuild the filesystem image to be as sparse as possible.
+
+ This method should be used by subclasses when staging the final image
+ in order to reduce the actual space taken up by the sparse image file
+ to be as little as possible.
+
+ This is done by resizing the filesystem to the minimal size (thereby
+ eliminating any space taken up by deleted files) and then resizing it
+ back to the supplied size.
+
+ size -- the size in, in bytes, which the filesystem image should be
+ resized to after it has been minimized; this defaults to None,
+ causing the original size specified by the kickstart file to
+ be used (or 4GiB if not specified in the kickstart).
+ """
+ minsize = 0
+ for item in self._instloops:
+ if 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
+
+ def _base_on(self, base_on=None):
+ if base_on and self._image != base_on:
+ shutil.copyfile(base_on, self._image)
+
+ def _check_imgdir(self):
+ if self._imgdir is None:
+ self._imgdir = self._mkdtemp()
+
+
+ #
+ # Actual implementation
+ #
+ def _mount_instroot(self, base_on=None):
+ if base_on and os.path.isfile(base_on):
+ self._imgdir = os.path.dirname(base_on)
+ imgname = os.path.basename(base_on)
+ self._base_on(base_on)
+ self._set_image_size(misc.get_file_size(self._image))
+
+ # here, self._instloops must be []
+ self._instloops.append({
+ "mountpoint": "/",
+ "label": self.name,
+ "name": imgname,
+ "size": self.__image_size or 4096,
+ "fstype": self.__fstype or "ext3",
+ "f2fsopts": None,
+ "extopts": None,
+ "loop": None,
+ "uuid": None,
+ "kspart": None,
+ "exclude_image" : None
+ })
+
+ self._check_imgdir()
+
+ for loop in self._instloops:
+ fstype = loop['fstype']
+ fsopt = loop['fsopts']
+ mp = os.path.join(self._instroot, loop['mountpoint'].lstrip('/'))
+ size = loop['size'] * 1024 * 1024
+ imgname = loop['name']
+
+ if fstype in ("ext2", "ext3", "ext4"):
+ MyDiskMount = fs.ExtDiskMount
+ elif fstype == "btrfs":
+ MyDiskMount = fs.BtrfsDiskMount
+ elif fstype in ("vfat", "msdos"):
+ MyDiskMount = fs.VfatDiskMount
+ elif fstype == "f2fs":
+ MyDiskMount = fs.F2fsDiskMount
+ else:
+ raise MountError('Cannot support fstype: %s' % fstype)
+
+ loop['loop'] = MyDiskMount(fs.SparseLoopbackDisk(
+ os.path.join(self._imgdir, imgname),
+ size),
+ mp,
+ fstype,
+ self._blocksize,
+ loop['fslabel'],
+ fsopt,
+ fsuuid = loop['uuid'])
+
+ if fstype in ("ext2", "ext3", "ext4"):
+ loop['loop'].extopts = loop['extopts']
+ elif fstype == "f2fs":
+ loop['loop'].f2fsopts = loop['f2fsopts']
+
+ try:
+ msger.verbose('Mounting image "%s" on "%s"' % (imgname, mp))
+ fs.makedirs(mp)
+ 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:
+ loop['kspart'].uuid = loop['loop'].uuid
+
+ except MountError as e:
+ raise
+
+ def _unmount_instroot(self):
+ for item in reversed(self._instloops):
+ try:
+ item['loop'].cleanup()
+ 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:
+ self._resparse(0)
+ else:
+ self._resparse()
+
+ for item in self._instloops:
+ imgfile = os.path.join(self._imgdir, item['name'])
+
+ if item['aft_fstype'] in AFTER_MNT_FS.keys():
+ mountpoint = misc.mkdtemp()
+ ext4img = os.path.join(self._imgdir, item['name'])
+ runner.show('mount -t ext4 %s %s' % (ext4img, mountpoint))
+ runner.show('ls -al %s' % (mountpoint))
+# item['loop'].mount(None, 'not_create')
+# point_mnt = os.path.join(self._instroot, item['mountpoint'].lstrip('/'))
+
+ fs_suffix = AFTER_MNT_FS[item['aft_fstype']]
+ if item['aft_fstype'] == "squashfs":
+# fs.mksquashfs(mountpoint, self._outdir+"/"+item['label']+fs_suffix)
+ args = "mksquashfs " + mountpoint + " " + self._imgdir+"/"+item['label']+fs_suffix
+ if item['squashfsopts']:
+ squashfsopts=item['squashfsopts'].replace(',', ' ')
+ runner.show("mksquashfs --help")
+ runner.show("%s %s" % (args, squashfsopts))
+ else:
+ runner.show("%s " % args)
+
+ if item['squashfsoptions_maxsize']:
+ squashfsoptions_maxsize=int(item['squashfsoptions_maxsize']) * 1024 * 1024
+ imgsize = os.stat(self._imgdir+"/"+item['label']+fs_suffix).st_size
+ if imgsize > squashfsoptions_maxsize:
+ msger.error("squashfs img size is too large (%d > %d)" % (imgsize, squashfsoptions_maxsize))
+ sys.exit()
+
+ if item['aft_fstype'] == "vdfs":
+ ##FIXME temporary code - replace this with fs.mkvdfs()
+ if item['vdfsopts']:
+ vdfsopts=item['vdfsopts'].replace(',', ' ')
+ else:
+ vdfsopts="-i -z 1024M"
+
+ fullpathmkvdfs = "mkfs.vdfs" #find_binary_path("mkfs.vdfs")
+ runner.show("%s --help" % fullpathmkvdfs)
+# fs.mkvdfs(mountpoint, self._outdir+"/"+item['label']+fs_suffix, vdfsopts)
+ 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)
+ runner.show('mv %s %s' % (self._imgdir+"/"+item['label']+fs_suffix, self._imgdir+"/"+item['label']+".img") )
+ runner.show('ls -al %s' % self._imgdir)
+
+ if item['fstype'] == "ext4":
+ 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:
+ compressing(imgfile, self.compress_image)
+ self.image_files.setdefault('image_files', []).append(
+ '.'.join([item['name'], self.compress_image]))
+ 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),
+ os.path.join(self._outdir, item))
+ else:
+ msger.info("Pack all loop images together to %s" % self.pack_to)
+ dstfile = os.path.join(self._outdir, self.pack_to)
+ packing(dstfile, self._imgdir)
+ self.image_files['image_files'] = [self.pack_to]
+
+
+ if self.pack_to:
+ mountfp_xml = os.path.splitext(self.pack_to)[0]
+ mountfp_xml = misc.strip_end(mountfp_xml, '.tar') + ".xml"
+ else:
+ mountfp_xml = self.name + ".xml"
+ # save mount points mapping file to xml
+ save_mountpoints(os.path.join(self._outdir, mountfp_xml),
+ self._instloops,
+ self.target_arch)
+
+ def copy_attachment(self):
+ if not hasattr(self, '_attachment') or not self._attachment:
+ return
+
+ self._check_imgdir()
+
+ msger.info("Copying attachment files...")
+ for item in self._attachment:
+ if not os.path.exists(item):
+ continue
+ dpath = os.path.join(self._imgdir, os.path.basename(item))
+ msger.verbose("Copy attachment %s to %s" % (item, dpath))
+ shutil.copy(item, dpath)
+
+ 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})
+ super(LoopImageCreator, self).create_manifest()
--- /dev/null
+#
+# Copyright (c) 2014 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+import shutil
+
+from mic.imager.loop import LoopImageCreator
+from mic.utils import errors, fs_related, runner
+
+class QcowImageCreator(LoopImageCreator):
+ img_format = 'qcow'
+
+ def __init__(self, creatoropts=None, pkgmgr=None):
+ LoopImageCreator.__init__(self, creatoropts, pkgmgr)
+ self.cmd_qemuimg = 'qemu-img'
+
+ def _stage_final_image(self):
+ try:
+ self.cmd_qemuimg = fs_related.find_binary_path('qemu-img')
+ except errors.CreatorError:
+ return LoopImageCreator._stage_final_image(self)
+
+ self._resparse()
+
+ imgfile = None
+ for item in self._instloops:
+ if item['mountpoint'] == '/':
+ if item['fstype'] == "ext4":
+ runner.show('/sbin/tune2fs -O ^huge_file,extents,uninit_bg %s'
+ % imgfile)
+ self.image_files.setdefault('partitions', {}).update(
+ {item['mountpoint']: item['label']})
+ imgfile = os.path.join(self._imgdir, item['name'])
+
+ if imgfile:
+ qemuimage = imgfile + ".x86"
+ runner.show("%s convert -O qcow2 %s %s"
+ % (self.cmd_qemuimg, imgfile, qemuimage))
+ os.unlink(imgfile)
+ os.rename(qemuimage, imgfile)
+
+ for item in os.listdir(self._imgdir):
+ shutil.move(os.path.join(self._imgdir, item),
+ os.path.join(self._outdir, item))
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+import stat
+import shutil
+
+from mic import kickstart, msger
+from mic.utils import fs_related, runner, misc
+from mic.utils.partitionedfs import PartitionedMount
+from mic.utils.errors import CreatorError, MountError
+from mic.imager.baseimager import BaseImageCreator
+from mic.archive import packing, compressing
+
+class RawImageCreator(BaseImageCreator):
+ """Installs a system into a file containing a partitioned disk image.
+
+ ApplianceImageCreator is an advanced ImageCreator subclass; a sparse file
+ is formatted with a partition table, each partition loopback mounted
+ and the system installed into an virtual disk. The disk image can
+ subsequently be booted in a virtual machine or accessed with kpartx
+ """
+ img_format = 'raw'
+
+ def __init__(self, creatoropts=None, pkgmgr=None, compress_image=None, generate_bmap=None, fstab_entry="uuid"):
+ """Initialize a ApplianceImageCreator instance.
+
+ This method takes the same arguments as ImageCreator.__init__()
+ """
+ BaseImageCreator.__init__(self, creatoropts, pkgmgr)
+
+ self.__instloop = None
+ self.__imgdir = None
+ self.__disks = {}
+ self.__disk_format = "raw"
+ self._disk_names = []
+ self._ptable_format = self.ks.handler.bootloader.ptable
+ self.vmem = 512
+ self.vcpu = 1
+ self.checksum = False
+ self.use_uuid = fstab_entry == "uuid"
+ self.appliance_version = None
+ self.appliance_release = None
+ self.compress_image = compress_image
+ self.bmap_needed = generate_bmap
+ self._need_extlinux = not kickstart.use_installerfw(self.ks, "bootloader")
+ #self.getsource = False
+ #self.listpkg = False
+
+ self._dep_checks.extend(["sync", "kpartx", "parted"])
+ if self._need_extlinux:
+ self._dep_checks.extend(["extlinux"])
+
+ def configure(self, repodata = None):
+ import subprocess
+ def chroot():
+ os.chroot(self._instroot)
+ os.chdir("/")
+
+ if os.path.exists(self._instroot + "/usr/bin/Xorg"):
+ subprocess.call(["/bin/chmod", "u+s", "/usr/bin/Xorg"],
+ preexec_fn = chroot)
+
+ BaseImageCreator.configure(self, repodata)
+
+ def _get_fstab(self):
+ s = ""
+ for mp in self.__instloop.mount_order:
+ p = None
+ for p1 in self.__instloop.partitions:
+ if p1['mountpoint'] == mp:
+ p = p1
+ break
+
+ if self.use_uuid and p['uuid']:
+ device = "UUID=%s" % p['uuid']
+ else:
+ device = "/dev/%s%-d" % (p['disk_name'], p['num'])
+
+ s += "%(device)s %(mountpoint)s %(fstype)s %(fsopts)s 0 0\n" % {
+ 'device': device,
+ 'mountpoint': p['mountpoint'],
+ 'fstype': p['fstype'],
+ 'fsopts': "defaults,noatime" if not p['fsopts'] else p['fsopts']}
+
+ if p['mountpoint'] == "/":
+ for subvol in self.__instloop.subvolumes:
+ if subvol['mountpoint'] == "/":
+ continue
+ s += "%(device)s %(mountpoint)s %(fstype)s %(fsopts)s 0 0\n" % {
+ 'device': "/dev/%s%-d" % (p['disk_name'], p['num']),
+ 'mountpoint': subvol['mountpoint'],
+ 'fstype': p['fstype'],
+ 'fsopts': "defaults,noatime" if not subvol['fsopts'] else subvol['fsopts']}
+
+ s += "devpts /dev/pts devpts gid=5,mode=620 0 0\n"
+ s += "tmpfs /dev/shm tmpfs defaults 0 0\n"
+ s += "proc /proc proc defaults 0 0\n"
+ s += "sysfs /sys sysfs defaults 0 0\n"
+ return s
+
+ def _create_mkinitrd_config(self):
+ """write to tell which modules to be included in initrd"""
+
+ mkinitrd = ""
+ mkinitrd += "PROBE=\"no\"\n"
+ mkinitrd += "MODULES+=\"ext3 ata_piix sd_mod libata scsi_mod\"\n"
+ mkinitrd += "rootfs=\"ext3\"\n"
+ mkinitrd += "rootopts=\"defaults\"\n"
+
+ msger.debug("Writing mkinitrd config %s/etc/sysconfig/mkinitrd" \
+ % self._instroot)
+ os.makedirs(self._instroot + "/etc/sysconfig/",mode=644)
+ cfg = open(self._instroot + "/etc/sysconfig/mkinitrd", "w")
+ cfg.write(mkinitrd)
+ cfg.close()
+
+ def _get_parts(self):
+ if not self.ks:
+ raise CreatorError("Failed to get partition info, "
+ "please check your kickstart setting.")
+
+ # Set a default partition if no partition is given out
+ if not self.ks.handler.partition.partitions:
+ partstr = "part / --size 1900 --ondisk sda --fstype=ext3"
+ args = partstr.split()
+ pd = self.ks.handler.partition.parse(args[1:])
+ if pd not in self.ks.handler.partition.partitions:
+ self.ks.handler.partition.partitions.append(pd)
+
+ # partitions list from kickstart file
+ return kickstart.get_partitions(self.ks)
+
+ def get_disk_names(self):
+ """ Returns a list of physical target disk names (e.g., 'sdb') which
+ will be created. """
+
+ if self._disk_names:
+ return self._disk_names
+
+ #get partition info from ks handler
+ parts = self._get_parts()
+
+ for i in range(len(parts)):
+ if parts[i].disk:
+ disk_name = parts[i].disk
+ else:
+ raise CreatorError("Failed to create disks, no --ondisk "
+ "specified in partition line of ks file")
+
+ if parts[i].mountpoint and not parts[i].fstype:
+ raise CreatorError("Failed to create disks, no --fstype "
+ "specified for partition with mountpoint "
+ "'%s' in the ks file")
+
+ self._disk_names.append(disk_name)
+
+ return self._disk_names
+
+ def _full_name(self, name, extention):
+ """ Construct full file name for a file we generate. """
+ return "%s-%s.%s" % (self.name, name, extention)
+
+ def _full_path(self, path, name, extention):
+ """ Construct full file path to a file we generate. """
+ return os.path.join(path, self._full_name(name, extention))
+
+ #
+ # Actual implemention
+ #
+ def _mount_instroot(self, base_on = None):
+ parts = self._get_parts()
+ self.__instloop = PartitionedMount(self._instroot)
+
+ for p in parts:
+ self.__instloop.add_partition(int(p.size),
+ p.disk,
+ p.mountpoint,
+ p.fstype,
+ p.label,
+ fsopts = p.fsopts,
+ boot = p.active,
+ align = p.align,
+ part_type = p.part_type)
+
+ self.__instloop.layout_partitions(self._ptable_format)
+
+ # Create the disks
+ self.__imgdir = self._mkdtemp()
+ for disk_name, disk in self.__instloop.disks.items():
+ full_path = self._full_path(self.__imgdir, disk_name, "raw")
+ msger.debug("Adding disk %s as %s with size %s bytes" \
+ % (disk_name, full_path, disk['min_size']))
+
+ disk_obj = fs_related.SparseLoopbackDisk(full_path,
+ disk['min_size'])
+ self.__disks[disk_name] = disk_obj
+ self.__instloop.add_disk(disk_name, disk_obj)
+
+ self.__instloop.mount()
+ self._create_mkinitrd_config()
+
+ def mount(self, base_on = None, cachedir = None):
+ """
+ This method calls the base class' 'mount()' method and then creates
+ block device nodes corresponding to the image's partitions in the image
+ itself. Namely, the image has /dev/loopX device corresponding to the
+ entire image, and per-partition /dev/mapper/* devices.
+
+ We copy these files to image's "/dev" directory in order to enable
+ scripts which run in the image chroot environment to access own raw
+ partitions. For example, this can be used to install the bootloader to
+ the MBR (say, from an installer framework plugin).
+ """
+
+ def copy_devnode(src, dest):
+ """A helper function for copying device nodes."""
+
+ if not src:
+ return
+
+ stat_obj = os.stat(src)
+ assert stat.S_ISBLK(stat_obj.st_mode)
+
+ os.mknod(dest, stat_obj.st_mode,
+ os.makedev(os.major(stat_obj.st_rdev),
+ os.minor(stat_obj.st_rdev)))
+ # os.mknod uses process umask may create a nod with different
+ # permissions, so we use os.chmod to make sure permissions are
+ # correct.
+ os.chmod(dest, stat_obj.st_mode)
+
+ BaseImageCreator.mount(self, base_on, cachedir)
+
+ # Copy the disk loop devices
+ for name in self.__disks.keys():
+ loopdev = self.__disks[name].device
+ copy_devnode(loopdev, self._instroot + loopdev)
+
+ # Copy per-partition dm nodes
+ os.mkdir(self._instroot + "/dev/mapper", os.stat("/dev/mapper").st_mode)
+ for p in self.__instloop.partitions:
+ copy_devnode(p['mapper_device'],
+ self._instroot + p['mapper_device'])
+ copy_devnode(p['mpath_device'],
+ self._instroot + p['mpath_device'])
+
+ def unmount(self):
+ """
+ Remove loop/dm device nodes which we created in 'mount()' and call the
+ base class' 'unmount()' method.
+ """
+
+ for p in self.__instloop.partitions:
+ if p['mapper_device']:
+ path = self._instroot + p['mapper_device']
+ if os.path.exists(path):
+ os.unlink(path)
+ if p['mpath_device']:
+ path = self._instroot + p['mpath_device']
+ if os.path.exists(path):
+ os.unlink(path)
+
+ path = self._instroot + "/dev/mapper"
+ if os.path.exists(path):
+ shutil.rmtree(path, ignore_errors=True)
+
+ for name in self.__disks.keys():
+ if self.__disks[name].device:
+ path = self._instroot + self.__disks[name].device
+ if os.path.exists(path):
+ os.unlink(path)
+
+ BaseImageCreator.unmount(self)
+
+ def _get_required_packages(self):
+ required_packages = BaseImageCreator._get_required_packages(self)
+ if self._need_extlinux:
+ if not self.target_arch or not self.target_arch.startswith("arm"):
+ required_packages += ["syslinux", "syslinux-extlinux"]
+ return required_packages
+
+ def _get_excluded_packages(self):
+ return BaseImageCreator._get_excluded_packages(self)
+
+ def _get_syslinux_boot_config(self):
+ rootdev = None
+ root_part_uuid = None
+ for p in self.__instloop.partitions:
+ if p['mountpoint'] == "/":
+ rootdev = "/dev/%s%-d" % (p['disk_name'], p['num'])
+ root_part_uuid = p['partuuid']
+
+ return (rootdev, root_part_uuid)
+
+ def _create_syslinux_config(self):
+
+ splash = os.path.join(self._instroot, "boot/extlinux")
+ if os.path.exists(splash):
+ splashline = "menu background splash.jpg"
+ else:
+ splashline = ""
+
+ (rootdev, root_part_uuid) = self._get_syslinux_boot_config()
+ options = self.ks.handler.bootloader.appendLine
+
+ #XXX don't hardcode default kernel - see livecd code
+ syslinux_conf = ""
+ syslinux_conf += "prompt 0\n"
+ syslinux_conf += "timeout 1\n"
+ syslinux_conf += "\n"
+ syslinux_conf += "default vesamenu.c32\n"
+ syslinux_conf += "menu autoboot Starting %s...\n" % self.distro_name
+ syslinux_conf += "menu hidden\n"
+ syslinux_conf += "\n"
+ syslinux_conf += "%s\n" % splashline
+ syslinux_conf += "menu title Welcome to %s!\n" % self.distro_name
+ syslinux_conf += "menu color border 0 #ffffffff #00000000\n"
+ syslinux_conf += "menu color sel 7 #ffffffff #ff000000\n"
+ syslinux_conf += "menu color title 0 #ffffffff #00000000\n"
+ syslinux_conf += "menu color tabmsg 0 #ffffffff #00000000\n"
+ syslinux_conf += "menu color unsel 0 #ffffffff #00000000\n"
+ syslinux_conf += "menu color hotsel 0 #ff000000 #ffffffff\n"
+ syslinux_conf += "menu color hotkey 7 #ffffffff #ff000000\n"
+ syslinux_conf += "menu color timeout_msg 0 #ffffffff #00000000\n"
+ syslinux_conf += "menu color timeout 0 #ffffffff #00000000\n"
+ syslinux_conf += "menu color cmdline 0 #ffffffff #00000000\n"
+
+ versions = []
+ kernels = self._get_kernel_versions()
+ symkern = "%s/boot/vmlinuz" % self._instroot
+
+ if os.path.lexists(symkern):
+ v = os.path.realpath(symkern).replace('%s-' % symkern, "")
+ syslinux_conf += "label %s\n" % self.distro_name.lower()
+ syslinux_conf += "\tmenu label %s (%s)\n" % (self.distro_name, v)
+ syslinux_conf += "\tlinux ../vmlinuz\n"
+ if self._ptable_format == 'msdos':
+ rootstr = rootdev
+ else:
+ if not root_part_uuid:
+ raise MountError("Cannot find the root GPT partition UUID")
+ rootstr = "PARTUUID=%s" % root_part_uuid
+ syslinux_conf += "\tappend ro root=%s %s\n" % (rootstr, options)
+ syslinux_conf += "\tmenu default\n"
+ else:
+ for kernel in kernels:
+ for version in kernels[kernel]:
+ versions.append(version)
+
+ footlabel = 0
+ for v in versions:
+ syslinux_conf += "label %s%d\n" \
+ % (self.distro_name.lower(), footlabel)
+ syslinux_conf += "\tmenu label %s (%s)\n" % (self.distro_name, v)
+ syslinux_conf += "\tlinux ../vmlinuz-%s\n" % v
+ syslinux_conf += "\tappend ro root=%s %s\n" \
+ % (rootdev, options)
+ if footlabel == 0:
+ syslinux_conf += "\tmenu default\n"
+ footlabel += 1
+
+ msger.debug("Writing syslinux config %s/boot/extlinux/extlinux.conf" \
+ % self._instroot)
+ cfg = open(self._instroot + "/boot/extlinux/extlinux.conf", "w")
+ cfg.write(syslinux_conf)
+ cfg.close()
+
+ def _install_syslinux(self):
+ for name in self.__disks.keys():
+ loopdev = self.__disks[name].device
+
+ # Set MBR
+ mbrfile = "%s/usr/share/syslinux/" % self._instroot
+ if self._ptable_format == 'gpt':
+ mbrfile += "gptmbr.bin"
+ else:
+ mbrfile += "mbr.bin"
+
+ msger.debug("Installing syslinux bootloader '%s' to %s" % \
+ (mbrfile, loopdev))
+
+ rc = runner.show(['dd', 'if=%s' % mbrfile, 'of=' + loopdev])
+ if rc != 0:
+ raise MountError("Unable to set MBR to %s" % loopdev)
+
+
+ # Ensure all data is flushed to disk before doing syslinux install
+ runner.quiet('sync')
+
+ fullpathsyslinux = fs_related.find_binary_path("extlinux")
+ rc = runner.show([fullpathsyslinux,
+ "-i",
+ "%s/boot/extlinux" % self._instroot])
+ if rc != 0:
+ raise MountError("Unable to install syslinux bootloader to %s" \
+ % loopdev)
+
+ def _create_bootconfig(self):
+ #If syslinux is available do the required configurations.
+ if self._need_extlinux \
+ and os.path.exists("%s/usr/share/syslinux/" % (self._instroot)) \
+ and os.path.exists("%s/boot/extlinux/" % (self._instroot)):
+ self._create_syslinux_config()
+ self._install_syslinux()
+
+ def _unmount_instroot(self):
+ if not self.__instloop is None:
+ try:
+ self.__instloop.cleanup()
+ except MountError as err:
+ msger.warning("%s" % err)
+
+ def _resparse(self, size = None):
+ return self.__instloop.resparse(size)
+
+ def _get_post_scripts_env(self, in_chroot):
+ env = BaseImageCreator._get_post_scripts_env(self, in_chroot)
+
+ # Export the file-system UUIDs and partition UUIDs (AKA PARTUUIDs)
+ for p in self.__instloop.partitions:
+ env.update(self._set_part_env(p['ks_pnum'], "UUID", p['uuid']))
+ env.update(self._set_part_env(p['ks_pnum'], "PARTUUID", p['partuuid']))
+ env.update(self._set_part_env(p['ks_pnum'], "DEVNODE_NOW",
+ p['mapper_device']))
+ env.update(self._set_part_env(p['ks_pnum'], "DISK_DEVNODE_NOW",
+ self.__disks[p['disk_name']].device))
+
+ return env
+
+ def _stage_final_image(self):
+ """Stage the final system image in _outdir.
+ write meta data
+ """
+ self._resparse()
+ self.image_files.update({'disks': self.__disks.keys()})
+
+ if not (self.compress_image or self.pack_to):
+ for imgfile in os.listdir(self.__imgdir):
+ if imgfile.endswith('.raw'):
+ for disk in self.__disks.keys():
+ if imgfile.find(disk) != -1:
+ self.image_files.setdefault(disk, {}).update(
+ {'image': imgfile})
+ self.image_files.setdefault('image_files',
+ []).append(imgfile)
+
+ if self.compress_image:
+ for imgfile in os.listdir(self.__imgdir):
+ if imgfile.endswith('.raw') or imgfile.endswith('bin'):
+ imgpath = os.path.join(self.__imgdir, imgfile)
+ msger.info("Compressing image %s" % imgfile)
+ compressing(imgpath, self.compress_image)
+ if imgfile.endswith('.raw') and not self.pack_to:
+ for disk in self.__disks.keys():
+ if imgfile.find(disk) != -1:
+ imgname = '%s.%s' % (imgfile, self.compress_image)
+ self.image_files.setdefault(disk, {}).update(
+ {'image': imgname})
+ self.image_files.setdefault('image_files',
+ []).append(imgname)
+
+ if self.pack_to:
+ dst = os.path.join(self._outdir, self.pack_to)
+ msger.info("Pack all raw images to %s" % dst)
+ packing(dst, self.__imgdir)
+ self.image_files.update({'image_files': self.pack_to})
+ else:
+ msger.debug("moving disks to stage location")
+ for imgfile in os.listdir(self.__imgdir):
+ src = os.path.join(self.__imgdir, imgfile)
+ dst = os.path.join(self._outdir, imgfile)
+ msger.debug("moving %s to %s" % (src,dst))
+ shutil.move(src,dst)
+
+ self._write_image_xml()
+
+ def _write_image_xml(self):
+ imgarch = "i686"
+ if self.target_arch:
+ if self.target_arch.startswith("arm"):
+ imgarch = "arm"
+ elif self.target_arch == "riscv64":
+ imgarch = "riscv64"
+ xml = "<image>\n"
+
+ name_attributes = ""
+ if self.appliance_version:
+ name_attributes += " version='%s'" % self.appliance_version
+ if self.appliance_release:
+ name_attributes += " release='%s'" % self.appliance_release
+ xml += " <name%s>%s</name>\n" % (name_attributes, self.name)
+ xml += " <domain>\n"
+ # XXX don't hardcode - determine based on the kernel we installed for
+ # grub baremetal vs xen
+ xml += " <boot type='hvm'>\n"
+ xml += " <guest>\n"
+ xml += " <arch>%s</arch>\n" % imgarch
+ xml += " </guest>\n"
+ xml += " <os>\n"
+ xml += " <loader dev='hd'/>\n"
+ xml += " </os>\n"
+
+ i = 0
+ for name in self.__disks.keys():
+ full_name = self._full_name(name, self.__disk_format)
+ xml += " <drive disk='%s' target='hd%s'/>\n" \
+ % (full_name, chr(ord('a') + i))
+ i = i + 1
+
+ xml += " </boot>\n"
+ xml += " <devices>\n"
+ xml += " <vcpu>%s</vcpu>\n" % self.vcpu
+ xml += " <memory>%d</memory>\n" %(self.vmem * 1024)
+ for network in self.ks.handler.network.network:
+ xml += " <interface/>\n"
+ xml += " <graphics/>\n"
+ xml += " </devices>\n"
+ xml += " </domain>\n"
+ xml += " <storage>\n"
+
+ if self.checksum is True:
+ for name in self.__disks.keys():
+ diskpath = self._full_path(self._outdir, name, \
+ self.__disk_format)
+ full_name = self._full_name(name, self.__disk_format)
+
+ msger.debug("Generating disk signature for %s" % full_name)
+
+ xml += " <disk file='%s' use='system' format='%s'>\n" \
+ % (full_name, self.__disk_format)
+
+ hashes = misc.calc_hashes(diskpath, ('sha1', 'sha256'))
+
+ xml += " <checksum type='sha1'>%s</checksum>\n" \
+ % hashes[0]
+ xml += " <checksum type='sha256'>%s</checksum>\n" \
+ % hashes[1]
+ xml += " </disk>\n"
+ else:
+ for name in self.__disks.keys():
+ full_name = self._full_name(name, self.__disk_format)
+ xml += " <disk file='%s' use='system' format='%s'/>\n" \
+ % (full_name, self.__disk_format)
+
+ xml += " </storage>\n"
+ xml += "</image>\n"
+
+ msger.debug("writing image XML to %s/%s.xml" %(self._outdir, self.name))
+ cfg = open("%s/%s.xml" % (self._outdir, self.name), "w")
+ cfg.write(xml)
+ cfg.close()
+
+ def generate_bmap(self):
+ """ Generate block map file for the image. The idea is that while disk
+ images we generate may be large (e.g., 4GiB), they may actually contain
+ only little real data, e.g., 512MiB. This data are files, directories,
+ file-system meta-data, partition table, etc. In other words, when
+ flashing the image to the target device, you do not have to copy all the
+ 4GiB of data, you can copy only 512MiB of it, which is 4 times faster.
+
+ This function generates the block map file for an arbitrary image that
+ mic has generated. The block map file is basically an XML file which
+ contains a list of blocks which have to be copied to the target device.
+ The other blocks are not used and there is no need to copy them. """
+
+ if self.bmap_needed is None:
+ return
+
+ msger.info("Generating the map file(s)")
+
+ for name in self.__disks.keys():
+ image = self._full_path(self.__imgdir, name, self.__disk_format)
+ bmap_file = self._full_path(self._outdir, name, "bmap")
+ self.image_files.setdefault(name, {}).update({'bmap': \
+ os.path.basename(bmap_file)})
+
+ msger.debug("Generating block map file '%s'" % bmap_file)
+
+ bmaptoolcmd = misc.find_binary_path('bmaptool')
+ rc = runner.show([bmaptoolcmd, 'create', image, '-o', bmap_file])
+ if rc != 0:
+ raise CreatorError("Failed to create bmap file: %s" % bmap_file)
+
+ def create_manifest(self):
+ if self.compress_image:
+ self.image_files.update({'compress': self.compress_image})
+ super(RawImageCreator, self).create_manifest()
+
+ def remove_exclude_image(self):
+ pass
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2007 Red Hat, Inc.
+# Copyright (c) 2009, 2010, 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os, sys, re
+import shutil
+import subprocess
+import string
+import collections
+
+import pykickstart.sections as kssections
+import pykickstart.commands as kscommands
+import pykickstart.constants as ksconstants
+import pykickstart.errors as kserrors
+import pykickstart.parser as ksparser
+import pykickstart.version as ksversion
+from pykickstart.handlers.control import commandMap
+from pykickstart.handlers.control import dataMap
+
+from mic import msger
+from mic.utils import errors, misc, runner, fs_related as fs
+from custom_commands import desktop, micrepo, micboot, partition, installerfw
+from mic.utils.safeurl import SafeURL
+
+AUTH_URL_PTN = r"(?P<scheme>.*)://(?P<username>.*)(:?P<password>.*)?@(?P<url>.*)"
+
+
+class PrepackageSection(kssections.Section):
+ sectionOpen = "%prepackages"
+
+ def handleLine(self, line):
+ if not self.handler:
+ return
+
+ (h, s, t) = line.partition('#')
+ line = h.rstrip()
+
+ self.handler.prepackages.add([line])
+
+ def handleHeader(self, lineno, args):
+ kssections.Section.handleHeader(self, lineno, args)
+
+class AttachmentSection(kssections.Section):
+ sectionOpen = "%attachment"
+
+ def handleLine(self, line):
+ if not self.handler:
+ return
+
+ (h, s, t) = line.partition('#')
+ line = h.rstrip()
+
+ self.handler.attachment.add([line])
+
+ 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:
+ func(*kargs, **kwargs)
+ except (OSError, IOError, errors.KsError) as err:
+ cfgcls = kargs[0].__class__.__name__
+ if msger.ask("Failed to apply %s, skip and continue?" % cfgcls):
+ msger.warning("%s" % err)
+ pass
+ else:
+ # just throw out the exception
+ raise
+ return wrapper
+
+def read_kickstart(path):
+ """Parse a kickstart file and return a KickstartParser instance.
+
+ This is a simple utility function which takes a path to a kickstart file,
+ parses it and returns a pykickstart KickstartParser instance which can
+ be then passed to an ImageCreator constructor.
+
+ If an error occurs, a CreatorError exception is thrown.
+ """
+
+ #version = ksversion.makeVersion()
+ #ks = ksparser.KickstartParser(version)
+
+ 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)
+
+ class KSHandlers(superclass):
+ def __init__(self):
+ superclass.__init__(self, mapping=commandMap[using_version])
+ self.prepackages = ksparser.Packages()
+ self.attachment = ksparser.Packages()
+
+ 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)
+ except (kserrors.KickstartParseError, kserrors.KickstartError) as err:
+ if msger.ask("Errors occured on kickstart file, skip and continue?"):
+ msger.warning("%s" % err)
+ pass
+ else:
+ raise errors.KsError("%s" % err)
+
+ return ks
+
+class KickstartConfig(object):
+ """A base class for applying kickstart configurations to a system."""
+ def __init__(self, instroot):
+ self.instroot = instroot
+
+ def path(self, subpath):
+ return self.instroot + subpath
+
+ def _check_sysconfig(self):
+ if not os.path.exists(self.path("/etc/sysconfig")):
+ fs.makedirs(self.path("/etc/sysconfig"))
+
+ def chroot(self):
+ os.chroot(self.instroot)
+ os.chdir("/")
+
+ def call(self, args):
+ if not os.path.exists("%s/%s" %(self.instroot, args[0])):
+ raise errors.KsError("Can't find %s in chroot" % args[0])
+ subprocess.call(args, preexec_fn = self.chroot)
+
+ def apply(self):
+ pass
+
+class LanguageConfig(KickstartConfig):
+ """A class to apply a kickstart language configuration to a system."""
+ @apply_wrapper
+ def apply(self, kslang):
+ self._check_sysconfig()
+ if kslang.lang:
+ f = open(self.path("/etc/sysconfig/i18n"), "w+")
+ f.write("LANG=\"" + kslang.lang + "\"\n")
+ f.close()
+
+ f = open(self.path("/etc/locale.conf"), "w+")
+ f.write("LANG=\"" + kslang.lang + "\"\n")
+ f.close()
+
+ #cp ks lang setting to other file, then can access the file in %post section
+ fs.makedirs(self.path("/etc/config"))
+ f = open(self.path("/etc/config/mic_language"), "w+")
+ f.write("LANG=\"" + kslang.lang + "\"\n")
+ f.close()
+
+class KeyboardConfig(KickstartConfig):
+ """A class to apply a kickstart keyboard configuration to a system."""
+ @apply_wrapper
+ def apply(self, kskeyboard):
+ #
+ # FIXME:
+ # should this impact the X keyboard config too?
+ # or do we want to make X be able to do this mapping?
+ #
+ #k = rhpl.keyboard.Keyboard()
+ #if kskeyboard.keyboard:
+ # k.set(kskeyboard.keyboard)
+ #k.write(self.instroot)
+ pass
+
+class TimezoneConfig(KickstartConfig):
+ """A class to apply a kickstart timezone configuration to a system."""
+ @apply_wrapper
+ def apply(self, kstimezone):
+ self._check_sysconfig()
+ tz = kstimezone.timezone or "America/New_York"
+ utc = str(kstimezone.isUtc)
+
+ f = open(self.path("/etc/sysconfig/clock"), "w+")
+ 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:
+ 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:
+ 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) as msg:
+ raise errors.KsError("Timezone setting error: %s" % msg)
+
+class AuthConfig(KickstartConfig):
+ """A class to apply a kickstart authconfig configuration to a system."""
+ @apply_wrapper
+ def apply(self, ksauthconfig):
+ auth = ksauthconfig.authconfig or "--useshadow --enablemd5"
+ args = ["/usr/share/authconfig/authconfig.py", "--update", "--nostart"]
+ self.call(args + auth.split())
+
+class FirewallConfig(KickstartConfig):
+ """A class to apply a kickstart firewall configuration to a system."""
+ @apply_wrapper
+ def apply(self, ksfirewall):
+ #
+ # FIXME: should handle the rest of the options
+ #
+ if not os.path.exists(self.path("/usr/sbin/lokkit")):
+ return
+ if ksfirewall.enabled:
+ status = "--enabled"
+ else:
+ status = "--disabled"
+
+ self.call(["/usr/sbin/lokkit",
+ "-f", "--quiet", "--nostart", status])
+
+class RootPasswordConfig(KickstartConfig):
+ """A class to apply a kickstart root password configuration to a system."""
+ def unset(self):
+ self.call(["/usr/bin/passwd", "-d", "root"])
+
+ def set_encrypted(self, password):
+ self.call(["/usr/sbin/usermod", "-p", password, "root"])
+
+ def set_unencrypted(self, password):
+ for p in ("/bin/echo", "/usr/sbin/chpasswd"):
+ if not os.path.exists("%s/%s" %(self.instroot, p)):
+ raise errors.KsError("Unable to set unencrypted password due "
+ "to lack of %s" % p)
+
+ p1 = subprocess.Popen(["/bin/echo", "root:%s" %password],
+ stdout = subprocess.PIPE,
+ preexec_fn = self.chroot)
+ p2 = subprocess.Popen(["/usr/sbin/chpasswd", "-c","SHA512"],
+ stdin = p1.stdout,
+ stdout = subprocess.PIPE,
+ preexec_fn = self.chroot)
+ p2.communicate()
+
+ @apply_wrapper
+ def apply(self, ksrootpw):
+ if ksrootpw.isCrypted:
+ self.set_encrypted(ksrootpw.password)
+ elif ksrootpw.password != "":
+ self.set_unencrypted(ksrootpw.password)
+ else:
+ self.unset()
+
+class UserConfig(KickstartConfig):
+ def set_empty_passwd(self, user):
+ self.call(["/usr/bin/passwd", "-d", user])
+
+ def set_encrypted_passwd(self, user, password):
+ self.call(["/usr/sbin/usermod", "-p", "%s" % password, user])
+
+ def set_unencrypted_passwd(self, user, password):
+ for p in ("/bin/echo", "/usr/sbin/chpasswd"):
+ if not os.path.exists("%s/%s" %(self.instroot, p)):
+ raise errors.KsError("Unable to set unencrypted password due "
+ "to lack of %s" % p)
+
+ p1 = subprocess.Popen(["/bin/echo", "%s:%s" %(user, password)],
+ stdout = subprocess.PIPE,
+ preexec_fn = self.chroot)
+ p2 = subprocess.Popen(["/usr/sbin/chpasswd", "-c","SHA512"],
+ stdin = p1.stdout,
+ stdout = subprocess.PIPE,
+ preexec_fn = self.chroot)
+ p2.communicate()
+
+ def addUser(self, userconfig):
+ args = [ "/usr/sbin/useradd" ]
+ if userconfig.groups:
+ args += [ "--groups", string.join(userconfig.groups, ",") ]
+ if userconfig.name:
+ args += [ "-m"]
+ args += [ "-d", "/home/%s" % userconfig.name ]
+ args.append(userconfig.name)
+ try:
+ dev_null = os.open("/dev/null", os.O_WRONLY)
+ msger.debug('adding user with %s' % args)
+ subprocess.call(args,
+ stdout = dev_null,
+ stderr = dev_null,
+ preexec_fn = self.chroot)
+ os.close(dev_null)
+ except:
+ msger.warning('Cannot add user using "useradd"')
+
+ if userconfig.password not in (None, ""):
+ if userconfig.isCrypted:
+ self.set_encrypted_passwd(userconfig.name,
+ userconfig.password)
+ else:
+ self.set_unencrypted_passwd(userconfig.name,
+ userconfig.password)
+ else:
+ self.set_empty_passwd(userconfig.name)
+ else:
+ raise errors.KsError("Invalid kickstart command: %s" \
+ % userconfig.__str__())
+
+ @apply_wrapper
+ def apply(self, user):
+ for userconfig in user.userList:
+ #There exist root user already.
+ if userconfig.name == "root":
+ msger.debug("root user, just set root user groups attribution")
+ if userconfig.groups:
+ self.call(["/usr/sbin/usermod", "-a", "-G", "%s" % string.join(userconfig.groups, ","), "root"])
+ continue
+ self.addUser(userconfig)
+
+class ServicesConfig(KickstartConfig):
+ """A class to apply a kickstart services configuration to a system."""
+ @apply_wrapper
+ def apply(self, ksservices):
+ if not os.path.exists(self.path("/sbin/chkconfig")):
+ return
+ for s in ksservices.enabled:
+ self.call(["/sbin/chkconfig", s, "on"])
+ for s in ksservices.disabled:
+ self.call(["/sbin/chkconfig", s, "off"])
+
+class XConfig(KickstartConfig):
+ """A class to apply a kickstart X configuration to a system."""
+ @apply_wrapper
+ def apply(self, ksxconfig):
+ if ksxconfig.startX and os.path.exists(self.path("/etc/inittab")):
+ f = open(self.path("/etc/inittab"), "r+")
+ buf = f.read()
+ buf = buf.replace("id:3:initdefault", "id:5:initdefault")
+ f.seek(0)
+ f.write(buf)
+ f.close()
+ if ksxconfig.defaultdesktop:
+ self._check_sysconfig()
+ f = open(self.path("/etc/sysconfig/desktop"), "w")
+ f.write("DESKTOP="+ksxconfig.defaultdesktop+"\n")
+ f.close()
+
+class DesktopConfig(KickstartConfig):
+ """A class to apply a kickstart desktop configuration to a system."""
+ @apply_wrapper
+ def apply(self, ksdesktop):
+ if ksdesktop.defaultdesktop:
+ self._check_sysconfig()
+ f = open(self.path("/etc/sysconfig/desktop"), "w")
+ f.write("DESKTOP="+ksdesktop.defaultdesktop+"\n")
+ f.close()
+ if os.path.exists(self.path("/etc/gdm/custom.conf")):
+ f = open(self.path("/etc/skel/.dmrc"), "w")
+ f.write("[Desktop]\n")
+ f.write("Session="+ksdesktop.defaultdesktop.lower()+"\n")
+ f.close()
+ if ksdesktop.session:
+ if os.path.exists(self.path("/etc/sysconfig/uxlaunch")):
+ f = open(self.path("/etc/sysconfig/uxlaunch"), "a+")
+ f.write("session="+ksdesktop.session.lower()+"\n")
+ f.close()
+ if ksdesktop.autologinuser:
+ self._check_sysconfig()
+ f = open(self.path("/etc/sysconfig/desktop"), "a+")
+ f.write("AUTOLOGIN_USER=" + ksdesktop.autologinuser + "\n")
+ f.close()
+ if os.path.exists(self.path("/etc/gdm/custom.conf")):
+ f = open(self.path("/etc/gdm/custom.conf"), "w")
+ f.write("[daemon]\n")
+ f.write("AutomaticLoginEnable=true\n")
+ f.write("AutomaticLogin=" + ksdesktop.autologinuser + "\n")
+ f.close()
+
+class MoblinRepoConfig(KickstartConfig):
+ """A class to apply a kickstart desktop configuration to a system."""
+ def __create_repo_section(self, repo, type, fd):
+ baseurl = None
+ mirrorlist = None
+ reposuffix = {"base":"", "debuginfo":"-debuginfo", "source":"-source"}
+ reponame = repo.name + reposuffix[type]
+ if type == "base":
+ if repo.baseurl:
+ baseurl = repo.baseurl
+ if repo.mirrorlist:
+ mirrorlist = repo.mirrorlist
+
+ elif type == "debuginfo":
+ if repo.baseurl:
+ if repo.baseurl.endswith("/"):
+ baseurl = os.path.dirname(os.path.dirname(repo.baseurl))
+ else:
+ baseurl = os.path.dirname(repo.baseurl)
+ baseurl += "/debug"
+
+ if repo.mirrorlist:
+ variant = repo.mirrorlist[repo.mirrorlist.find("$"):]
+ mirrorlist = repo.mirrorlist[0:repo.mirrorlist.find("$")]
+ mirrorlist += "debug" + "-" + variant
+
+ elif type == "source":
+ if repo.baseurl:
+ if repo.baseurl.endswith("/"):
+ baseurl = os.path.dirname(
+ os.path.dirname(
+ os.path.dirname(repo.baseurl)))
+ else:
+ baseurl = os.path.dirname(os.path.dirname(repo.baseurl))
+ baseurl += "/source"
+
+ if repo.mirrorlist:
+ variant = repo.mirrorlist[repo.mirrorlist.find("$"):]
+ mirrorlist = repo.mirrorlist[0:repo.mirrorlist.find("$")]
+ mirrorlist += "source" + "-" + variant
+
+ fd.write("[" + reponame + "]\n")
+ fd.write("name=" + reponame + "\n")
+ fd.write("failovermethod=priority\n")
+ if baseurl:
+ auth_url = re.compile(AUTH_URL_PTN)
+ m = auth_url.match(baseurl)
+ if m:
+ baseurl = "%s://%s" % (m.group('scheme'), m.group('url'))
+ fd.write("baseurl=" + baseurl + "\n")
+ if mirrorlist:
+ fd.write("mirrorlist=" + mirrorlist + "\n")
+ """ Skip saving proxy settings """
+ #if repo.proxy:
+ # fd.write("proxy=" + repo.proxy + "\n")
+ #if repo.proxy_username:
+ # fd.write("proxy_username=" + repo.proxy_username + "\n")
+ #if repo.proxy_password:
+ # fd.write("proxy_password=" + repo.proxy_password + "\n")
+ if repo.gpgkey:
+ fd.write("gpgkey=" + repo.gpgkey + "\n")
+ fd.write("gpgcheck=1\n")
+ else:
+ fd.write("gpgcheck=0\n")
+ if type == "source" or type == "debuginfo" or repo.disable:
+ fd.write("enabled=0\n")
+ else:
+ fd.write("enabled=1\n")
+ fd.write("\n")
+
+ def __create_repo_file(self, repo, repodir):
+ fs.makedirs(self.path(repodir))
+ f = open(self.path(repodir + "/" + repo.name + ".repo"), "w")
+ self.__create_repo_section(repo, "base", f)
+ if repo.debuginfo:
+ self.__create_repo_section(repo, "debuginfo", f)
+ if repo.source:
+ self.__create_repo_section(repo, "source", f)
+ f.close()
+
+ @apply_wrapper
+ def apply(self, ksrepo, repodata, repourl):
+ for repo in ksrepo.repoList:
+ if repo.name in repourl:
+ repo.baseurl = repourl[repo.name]
+ if repo.save:
+ #self.__create_repo_file(repo, "/etc/yum.repos.d")
+ self.__create_repo_file(repo, "/etc/zypp/repos.d")
+ """ Import repo gpg keys """
+ if repodata:
+ for repo in repodata:
+ if repo['repokey']:
+ runner.quiet(['rpm',
+ "--root=%s" % self.instroot,
+ "--import",
+ repo['repokey']])
+
+class RPMMacroConfig(KickstartConfig):
+ """A class to apply the specified rpm macros to the filesystem"""
+ @apply_wrapper
+ def apply(self, ks):
+ if not ks:
+ return
+ if not os.path.exists(self.path("/etc/rpm")):
+ os.mkdir(self.path("/etc/rpm"))
+ f = open(self.path("/etc/rpm/macros.imgcreate"), "w+")
+ if exclude_docs(ks):
+ f.write("%_excludedocs 1\n")
+ f.write("%__file_context_path %{nil}\n")
+ if inst_langs(ks) != None:
+ f.write("%_install_langs ")
+ f.write(inst_langs(ks))
+ f.write("\n")
+ f.close()
+
+class NetworkConfig(KickstartConfig):
+ """A class to apply a kickstart network configuration to a system."""
+ def write_ifcfg(self, network):
+ p = self.path("/etc/sysconfig/network-scripts/ifcfg-" + network.device)
+
+ f = file(p, "w+")
+ os.chmod(p, 0o644)
+
+ f.write("DEVICE=%s\n" % network.device)
+ f.write("BOOTPROTO=%s\n" % network.bootProto)
+
+ if network.bootProto.lower() == "static":
+ if network.ip:
+ f.write("IPADDR=%s\n" % network.ip)
+ if network.netmask:
+ f.write("NETMASK=%s\n" % network.netmask)
+
+ if network.onboot:
+ f.write("ONBOOT=on\n")
+ else:
+ f.write("ONBOOT=off\n")
+
+ if network.essid:
+ f.write("ESSID=%s\n" % network.essid)
+
+ if network.ethtool:
+ if network.ethtool.find("autoneg") == -1:
+ network.ethtool = "autoneg off " + network.ethtool
+ f.write("ETHTOOL_OPTS=%s\n" % network.ethtool)
+
+ if network.bootProto.lower() == "dhcp":
+ if network.hostname:
+ f.write("DHCP_HOSTNAME=%s\n" % network.hostname)
+ if network.dhcpclass:
+ f.write("DHCP_CLASSID=%s\n" % network.dhcpclass)
+
+ if network.mtu:
+ f.write("MTU=%s\n" % network.mtu)
+
+ f.close()
+
+ def write_wepkey(self, network):
+ if not network.wepkey:
+ return
+
+ p = self.path("/etc/sysconfig/network-scripts/keys-" + network.device)
+ f = file(p, "w+")
+ os.chmod(p, 0o600)
+ f.write("KEY=%s\n" % network.wepkey)
+ f.close()
+
+ def write_sysconfig(self, useipv6, hostname, gateway):
+ path = self.path("/etc/sysconfig/network")
+ f = file(path, "w+")
+ os.chmod(path, 0o644)
+
+ f.write("NETWORKING=yes\n")
+
+ if useipv6:
+ f.write("NETWORKING_IPV6=yes\n")
+ else:
+ f.write("NETWORKING_IPV6=no\n")
+
+ if hostname:
+ f.write("HOSTNAME=%s\n" % hostname)
+ else:
+ f.write("HOSTNAME=localhost.localdomain\n")
+
+ if gateway:
+ f.write("GATEWAY=%s\n" % gateway)
+
+ f.close()
+
+ def write_hosts(self, hostname):
+ localline = ""
+ if hostname and hostname != "localhost.localdomain":
+ localline += hostname + " "
+ l = hostname.split(".")
+ if len(l) > 1:
+ localline += l[0] + " "
+ localline += "localhost.localdomain localhost"
+
+ path = self.path("/etc/hosts")
+ f = file(path, "w+")
+ os.chmod(path, 0o644)
+ f.write("127.0.0.1\t\t%s\n" % localline)
+ f.write("::1\t\tlocalhost6.localdomain6 localhost6\n")
+ f.close()
+
+ def write_resolv(self, nodns, nameservers):
+ if nodns or not nameservers:
+ return
+
+ path = self.path("/etc/resolv.conf")
+ f = file(path, "w+")
+ os.chmod(path, 0o644)
+
+ for ns in (nameservers):
+ if ns:
+ f.write("nameserver %s\n" % ns)
+
+ f.close()
+
+ @apply_wrapper
+ def apply(self, ksnet):
+ fs.makedirs(self.path("/etc/sysconfig/network-scripts"))
+
+ useipv6 = False
+ nodns = False
+ hostname = None
+ gateway = None
+ nameservers = None
+
+ for network in ksnet.network:
+ if not network.device:
+ raise errors.KsError("No --device specified with "
+ "network kickstart command")
+
+ if (network.onboot and network.bootProto.lower() != "dhcp" and
+ not (network.ip and network.netmask)):
+ raise errors.KsError("No IP address and/or netmask "
+ "specified with static "
+ "configuration for '%s'" %
+ network.device)
+
+ self.write_ifcfg(network)
+ self.write_wepkey(network)
+
+ if network.ipv6:
+ useipv6 = True
+ if network.nodns:
+ nodns = True
+
+ if network.hostname:
+ hostname = network.hostname
+ if network.gateway:
+ gateway = network.gateway
+
+ if network.nameserver:
+ nameservers = network.nameserver.split(",")
+
+ self.write_sysconfig(useipv6, hostname, gateway)
+
+ #to avoid import error because of import each other
+ from mic.conf import configmgr
+ path=self.path("/etc/hosts")
+ if configmgr.create['skip_set_hosts'] == False and os.path.exists(path) == False:
+ self.write_hosts(hostname)
+ self.write_resolv(nodns, nameservers)
+
+def use_installerfw(ks, feature):
+ """ Check if the installer framework has to be used for a feature
+ "feature". """
+
+ features = ks.handler.installerfw.features
+ if features:
+ if feature in features or "all" in features:
+ return True
+ return False
+
+def get_image_size(ks, default = None):
+ __size = 0
+ for p in ks.handler.partition.partitions:
+ if p.mountpoint == "/" and p.size:
+ __size = p.size
+ if __size > 0:
+ return int(__size) * 1024 * 1024
+ else:
+ return default
+
+def get_image_fstype(ks, default = None):
+ for p in ks.handler.partition.partitions:
+ if p.mountpoint == "/" and p.fstype:
+ return p.fstype
+ return default
+
+def get_image_fsopts(ks, default = None):
+ for p in ks.handler.partition.partitions:
+ if p.mountpoint == "/" and p.fsopts:
+ return p.fsopts
+ return default
+
+def get_modules(ks):
+ devices = []
+ if isinstance(ks.handler.device, kscommands.device.FC3_Device):
+ devices.append(ks.handler.device)
+ else:
+ devices.extend(ks.handler.device.deviceList)
+
+ modules = []
+ for device in devices:
+ if not device.moduleName:
+ continue
+ modules.extend(device.moduleName.split(":"))
+
+ return modules
+
+def get_timeout(ks, default = None):
+ if not hasattr(ks.handler.bootloader, "timeout"):
+ return default
+ if ks.handler.bootloader.timeout is None:
+ return default
+ return int(ks.handler.bootloader.timeout)
+
+def get_kernel_args(ks, default = "ro rd.live.image"):
+ if not hasattr(ks.handler.bootloader, "appendLine"):
+ return default
+ if ks.handler.bootloader.appendLine is None:
+ return default
+ return "%s %s" %(default, ks.handler.bootloader.appendLine)
+
+def get_menu_args(ks, default = ""):
+ if not hasattr(ks.handler.bootloader, "menus"):
+ return default
+ if ks.handler.bootloader.menus in (None, ""):
+ return default
+ return "%s" % ks.handler.bootloader.menus
+
+def get_default_kernel(ks, default = None):
+ if not hasattr(ks.handler.bootloader, "default"):
+ return default
+ if not ks.handler.bootloader.default:
+ return default
+ return ks.handler.bootloader.default
+
+RepoType = collections.namedtuple("Repo",
+ "name, baseurl, mirrorlist, includepkgs, excludepkgs, proxy, \
+ proxy_username, proxy_password, debuginfo, \
+ source, gpgkey, disable, ssl_verify, nocache, \
+ cost, priority")
+
+def Repo(name, baseurl, mirrorlist=None, includepkgs=[], excludepkgs=[], proxy=None,
+ proxy_username=None, proxy_password=None, debuginfo=None,
+ source=None, gpgkey=None, disable=None, ssl_verify=None,
+ nocache=False, cost=None, priority=None):
+ return RepoType(name, baseurl, mirrorlist, includepkgs, excludepkgs, proxy,
+ proxy_username, proxy_password, debuginfo,
+ source, gpgkey, disable, ssl_verify, nocache,
+ cost, priority)
+
+
+def get_repos(ks, repo_urls=None, ignore_ksrepo=False):
+ repos = {}
+ for repodata in ks.handler.repo.repoList:
+ repo = {}
+ for field in RepoType._fields:
+ if hasattr(repodata, field) and getattr(repodata, field):
+ repo[field] = getattr(repodata, field)
+
+ if hasattr(repodata, 'baseurl') and getattr(repodata, 'baseurl'):
+ repo['baseurl'] = SafeURL(getattr(repodata, 'baseurl'),
+ getattr(repodata, 'user', None),
+ getattr(repodata, 'passwd', None))
+
+ if 'name' in repo:
+ repos[repo['name']] = Repo(**repo)
+
+ if repo_urls:
+ if ignore_ksrepo:
+ repos = {}
+ for name, repo in repo_urls.items():
+ if 'baseurl' in repo:
+ repo['baseurl'] = SafeURL(repo.get('baseurl'),
+ 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()
+ except (AttributeError, kserrors.KickstartError):
+ pass
+
+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)
+
+def get_excluded(ks, required=()):
+ return ks.handler.packages.excludedList + list(required)
+
+def get_partitions(ks):
+ return ks.handler.partition.partitions
+
+def ignore_missing(ks):
+ return ks.handler.packages.handleMissing == ksconstants.KS_MISSING_IGNORE
+
+def exclude_docs(ks):
+ return ks.handler.packages.excludeDocs
+
+def inst_langs(ks):
+ if hasattr(ks.handler.packages, "instLange"):
+ return ks.handler.packages.instLange
+ elif hasattr(ks.handler.packages, "instLangs"):
+ return ks.handler.packages.instLangs
+ return ""
+
+def get_post_scripts(ks):
+ scripts = []
+ for s in ks.handler.scripts:
+ if s.type != ksparser.KS_SCRIPT_POST:
+ continue
+ 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:])
+ if repoobj and repoobj not in ks.handler.repo.repoList:
+ ks.handler.repo.repoList.append(repoobj)
+
+def remove_all_repos(ks):
+ while len(ks.handler.repo.repoList) != 0:
+ del ks.handler.repo.repoList[0]
+
+def remove_duplicate_repos(ks):
+ i = 0
+ j = i + 1
+ while True:
+ if len(ks.handler.repo.repoList) < 2:
+ break
+ if i >= len(ks.handler.repo.repoList) - 1:
+ break
+ name = ks.handler.repo.repoList[i].name
+ baseurl = ks.handler.repo.repoList[i].baseurl
+ if j < len(ks.handler.repo.repoList):
+ if (ks.handler.repo.repoList[j].name == name or \
+ ks.handler.repo.repoList[j].baseurl == baseurl):
+ del ks.handler.repo.repoList[j]
+ else:
+ j += 1
+ if j >= len(ks.handler.repo.repoList):
+ i += 1
+ j = i + 1
+ else:
+ i += 1
+ j = i + 1
+
+def resolve_groups(creatoropts, repometadata):
+ iszypp = False
+ if 'zypp' == creatoropts['pkgmgr']:
+ iszypp = True
+ ks = creatoropts['ks']
+
+ for repo in repometadata:
+ """ Mustn't replace group with package list if repo is ready for the
+ corresponding package manager.
+ """
+
+ if iszypp and repo["patterns"]:
+ continue
+ if not iszypp and repo["comps"]:
+ continue
+
+ # But we also must handle such cases, use zypp but repo only has comps,
+ # use yum but repo only has patterns, use zypp but use_comps is true,
+ # use yum but use_comps is false.
+ groupfile = None
+ if iszypp and repo["comps"]:
+ groupfile = repo["comps"]
+ get_pkglist_handler = misc.get_pkglist_in_comps
+ if not iszypp and repo["patterns"]:
+ groupfile = repo["patterns"]
+ get_pkglist_handler = misc.get_pkglist_in_patterns
+
+ if groupfile:
+ i = 0
+ while True:
+ if i >= len(ks.handler.packages.groupList):
+ break
+ pkglist = get_pkglist_handler(
+ ks.handler.packages.groupList[i].name,
+ groupfile)
+ if pkglist:
+ del ks.handler.packages.groupList[i]
+ for pkg in pkglist:
+ if pkg not in ks.handler.packages.packageList:
+ ks.handler.packages.packageList.append(pkg)
+ else:
+ i = i + 1
--- /dev/null
+from desktop import Mic_Desktop
+from micrepo import Mic_Repo, Mic_RepoData,Mic_Tpk_Repo, Mic_Tpk_RepoData
+from partition import Mic_Partition
+from installerfw import Mic_installerfw
+
+__all__ = (
+ "Mic_Desktop",
+ "Mic_Repo",
+ "Mic_RepoData",
+ "Mic_Tpk_Repo",
+ "Mic_Tpk_RepoData",
+ "Mic_Partition",
+ "Mic_installerfw",
+)
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2008, 2009, 2010 Intel, Inc.
+#
+# Yi Yang <yi.y.yang@intel.com>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+
+class Mic_Desktop(KickstartCommand):
+ def __init__(self, writePriority=0,
+ defaultdesktop=None,
+ defaultdm=None,
+ autologinuser=None,
+ session=None):
+
+ KickstartCommand.__init__(self, writePriority)
+
+ self.__new_version = False
+ self.op = self._getParser()
+
+ self.defaultdesktop = defaultdesktop
+ self.autologinuser = autologinuser
+ self.defaultdm = defaultdm
+ self.session = session
+
+ def __str__(self):
+ retval = ""
+
+ if self.defaultdesktop != None:
+ retval += " --defaultdesktop=%s" % self.defaultdesktop
+ if self.session != None:
+ retval += " --session=\"%s\"" % self.session
+ if self.autologinuser != None:
+ retval += " --autologinuser=%s" % self.autologinuser
+ if self.defaultdm != None:
+ retval += " --defaultdm=%s" % self.defaultdm
+
+ if retval != "":
+ retval = "# Default Desktop Settings\ndesktop %s\n" % retval
+
+ return retval
+
+ def _getParser(self):
+ try:
+ #ingnore this pylit error, the lineno argument exist in olg version. using this way can compate old version.
+ op = KSOptionParser(lineno=self.lineno) #pylint: disable=unexpected-keyword-arg
+ except TypeError:
+ # the latest version has not lineno argument
+ op = KSOptionParser()
+ self.__new_version = True
+
+ op.add_option("--defaultdesktop", dest="defaultdesktop",
+ action="store",
+ type="string",
+ nargs=1)
+ op.add_option("--autologinuser", dest="autologinuser",
+ action="store",
+ type="string",
+ nargs=1)
+ op.add_option("--defaultdm", dest="defaultdm",
+ action="store",
+ type="string",
+ nargs=1)
+ op.add_option("--session", dest="session",
+ action="store",
+ type="string",
+ nargs=1)
+ return op
+
+ def parse(self, args):
+ if self.__new_version:
+ (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+ else:
+ (opts, extra) = self.op.parse_args(args=args)
+
+ if extra:
+ m = ("Unexpected arguments to %(command)s command: %(options)s") \
+ % {"command": "desktop", "options": extra}
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg=m))
+
+ self._setToSelf(self.op, opts)
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2013 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+from pykickstart.base import *
+from pykickstart.options import *
+from mic import msger
+
+class Mic_installerfw(KickstartCommand):
+ """ This class implements the "installerfw_plugins" KS option. The argument
+ of the option is a comman-separated list of MIC features which have to be
+ disabled and instead, will be done in the installer. For example,
+ "installerfw_plugins=bootloader" disables all the MIC code which installs
+ the bootloader to the target images, and instead, the bootlodaer will be
+ installed by the installer framework plugin.
+
+ The plugin is a program which is external to MIC, it comes from the
+ installation repositories and can be executed by MIC in order to perform
+ various configuration actions. The main point here is to make sure MIC has
+ no hard-wired knoledge about the target OS configuration. """
+
+ removedKeywords = KickstartCommand.removedKeywords
+ removedAttrs = KickstartCommand.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ KickstartCommand.__init__(self, *args, **kwargs)
+ self.op = self._getParser()
+ self.features = None
+
+ def __str__(self):
+ retval = KickstartCommand.__str__(self)
+
+ if self.features:
+ retval += "# Enable installer framework plugins\ninstallerfw_plugins\n"
+
+ return retval
+
+ def _getParser(self):
+ op = KSOptionParser()
+ return op
+
+ def parse(self, args):
+ (_, extra) = self.op.parse_args(args=args, lineno=self.lineno)
+
+ if len(extra) != 1:
+ msg = "Kickstart command \"%s\" requires one " \
+ "argumet - a list of legacy features to disable" % self.currentCmd
+ raise KickstartValueError (formatErrorMsg(self.lineno, msg = msg))
+
+ self.features = extra[0].split(",")
+
+ return self
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2008, 2009, 2010 Intel, Inc.
+#
+# Anas Nashif
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+from pykickstart.base import *
+from pykickstart.errors import *
+from pykickstart.options import *
+from pykickstart.commands.bootloader import *
+
+class Mic_Bootloader(F8_Bootloader):
+ def __init__(self, writePriority=10, appendLine="", driveorder=None,
+ forceLBA=False, location="", md5pass="", password="",
+ upgrade=False, menus=""):
+ F8_Bootloader.__init__(self, writePriority, appendLine, driveorder,
+ forceLBA, location, md5pass, password, upgrade)
+
+ self.menus = ""
+ self.ptable = "msdos"
+
+ def _getArgsAsStr(self):
+ ret = F8_Bootloader._getArgsAsStr(self)
+
+ if self.menus == "":
+ ret += " --menus=%s" %(self.menus,)
+ if self.ptable:
+ ret += " --ptable=\"%s\"" %(self.ptable,)
+ return ret
+
+ def _getParser(self):
+ op = F8_Bootloader._getParser(self)
+ op.add_option("--menus", dest="menus")
+ op.add_option("--ptable", dest="ptable", type="string")
+ return op
+
--- /dev/null
+#
+# Copyright (c) 2008, 2009, 2010 Intel, Inc.
+#
+# Yi Yang <yi.y.yang@intel.com>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+from pykickstart.commands.repo import F14_RepoData, F14_Repo
+
+
+class Mic_RepoData(F14_RepoData):
+ "Mic customized repo data"
+
+ def __init__(self, *args, **kw):
+ F14_RepoData.__init__(self, *args, **kw)
+ for field in ('save', 'proxyuser', 'proxypasswd', 'debuginfo',
+ 'disable', 'source', 'gpgkey', 'ssl_verify', 'priority',
+ 'nocache', 'user', 'passwd'):
+ setattr(self, field, kw.get(field))
+
+ if hasattr(self, 'proxy') and not self.proxy:
+ # TODO: remove this code, since it only for back-compatible.
+ # Some code behind only accept None but not empty string
+ # for default proxy
+ self.proxy = None
+
+ def _getArgsAsStr(self):
+ retval = F14_RepoData._getArgsAsStr(self)
+
+ for field in ('proxyuser', 'proxypasswd', 'user', 'passwd',
+ 'gpgkey', 'ssl_verify', 'priority',
+ ):
+ if hasattr(self, field) and getattr(self, field):
+ retval += ' --%s="%s"' % (field, getattr(self, field))
+
+ for field in ('save', 'diable', 'nocache', 'source', 'debuginfo'):
+ if hasattr(self, field) and getattr(self, field):
+ retval += ' --%s' % field
+
+ 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"
+
+ def _getParser(self):
+ op = F14_Repo._getParser(self)
+ op.add_option('--user')
+ op.add_option('--passwd')
+ op.add_option("--proxyuser")
+ op.add_option("--proxypasswd")
+
+ op.add_option("--save", action="store_true", default=False)
+ op.add_option("--debuginfo", action="store_true", default=False)
+ op.add_option("--source", action="store_true", default=False)
+ op.add_option("--disable", action="store_true", default=False)
+ op.add_option("--nocache", action="store_true", default=False)
+
+ op.add_option("--gpgkey")
+ 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
+
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Marko Saukko <marko.saukko@cybercom.com>
+#
+# Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+#
+# This copyrighted material is made available to anyone wishing to use, modify,
+# copy, or redistribute it subject to the terms and conditions of the GNU
+# General Public License v.2. This program is distributed in the hope that it
+# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
+# implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+from pykickstart.commands.partition import *
+
+class Mic_PartData(FC4_PartData):
+ removedKeywords = FC4_PartData.removedKeywords
+ removedAttrs = FC4_PartData.removedAttrs
+
+ def __init__(self, *args, **kwargs):
+ FC4_PartData.__init__(self, *args, **kwargs)
+ self.deleteRemovedAttrs()
+ self.align = kwargs.get("align", None)
+ self.extopts = kwargs.get("extopts", None)
+ self.f2fsopts = kwargs.get("f2fsopts", None)
+ self.part_type = kwargs.get("part_type", None)
+ self.uuid = kwargs.get("uuid", None)
+ self.exclude_image = kwargs.get("exclude_from_image", False)
+ self.vdfsopts = kwargs.get("vdfsopts", None)
+ self.squashfsopts = kwargs.get("squashfsopts", None)
+ self.squashfsoptions_maxsize = kwargs.get("squashfsoptions_maxsize", 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)
+
+ if self.align:
+ retval += " --align"
+ if self.extopts:
+ retval += " --extoptions=%s" % self.extopts
+ if self.f2fsopts:
+ retval += " --f2fsoptions=%s" % self.f2fsopts
+ if self.part_type:
+ retval += " --part-type=%s" % self.part_type
+ if self.uuid:
+ retval += " --uuid=%s" % self.uuid
+ if self.exclude_image:
+ retval += " --exclude-from-image"
+ if self.vdfsopts:
+ retval += " --vdfsoptions=%s" % self.vdfsopts
+ if self.squashfsopts:
+ retval += " --squashfsoptions=%s" % self.squashfsopts
+ if self.squashfsoptions_maxsize:
+ retval += " --squashfsoptions_maxsize=%s" % self.squashfsoptions_maxsize
+ 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):
+ removedKeywords = FC4_Partition.removedKeywords
+ removedAttrs = FC4_Partition.removedAttrs
+
+ def _getParser(self):
+ op = FC4_Partition._getParser(self)
+ # The alignment value is given in kBytes. e.g., value 8 means that
+ # the partition is aligned to start from 8096 byte boundary.
+ op.add_option("--align", type="int", action="store", dest="align",
+ default=None)
+ op.add_option("--extoptions", type="string", action="store", dest="extopts",
+ default=None)
+ op.add_option("--f2fsoptions", type="string", action="store", dest="f2fsopts",
+ default=None)
+ op.add_option("--part-type", type="string", action="store", dest="part_type",
+ default=None)
+ op.add_option("--uuid", dest="uuid", action="store", type="string")
+ op.add_option("--exclude-from-image", action="store_true", dest="exclude_image",
+ default=False)
+ op.add_option("--vdfsoptions", type="string", action="store", dest="vdfsopts",
+ default=None)
+ op.add_option("--squashfsoptions", type="string", action="store", dest="squashfsopts",
+ default=None)
+ op.add_option("--squashfsoptions_maxsize", type="string", action="store", dest="squashfsoptions_maxsize",
+ 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
--- /dev/null
+#
+# Copyright (c) 2013 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# Following messages should be disabled in pylint:
+# * Too many instance attributes (R0902)
+# * Too few public methods (R0903)
+# * Too many public methods (R0904)
+# * Anomalous backslash in string (W1401)
+# * __init__ method from base class %r is not called (W0231)
+# * __init__ method from a non direct base class %r is called (W0233)
+# * Invalid name for type (C0103)
+# * RootLogger has no '%s' member (E1103)
+# pylint: disable=R0902,R0903,R0904,W1401,W0231,W0233,C0103,E1103
+
+""" This logging module is fully compatible with the old msger module, and
+ it supports interactive mode, logs the messages with specified levels
+ to specified stream, can also catch all error messages including the
+ involved 3rd party modules to the logger
+"""
+import os
+import sys
+import logging
+import tempfile
+
+__ALL__ = [
+ 'get_loglevel',
+ 'set_loglevel',
+ 'set_logfile',
+ 'enable_interactive',
+ 'disable_interactive',
+ 'enable_logstderr',
+ 'disable_logstderr',
+ 'raw',
+ 'debug',
+ 'verbose',
+ 'info',
+ 'warning',
+ 'error',
+ 'select',
+ 'choice',
+ 'ask',
+ 'pause',
+]
+
+
+# define the color constants
+BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(30, 38)
+
+# color sequence for tty terminal
+COLOR_SEQ = "\033[%dm"
+# reset sequence for tty terminal
+RESET_SEQ = "\033[0m"
+
+# new log level
+RAWTEXT = 25
+VERBOSE = 15
+
+# define colors for log levels
+COLORS = {
+ 'DEBUG': COLOR_SEQ % BLUE,
+ 'VERBOSE': COLOR_SEQ % MAGENTA,
+ 'INFO': COLOR_SEQ % GREEN,
+ 'WARNING': COLOR_SEQ % YELLOW,
+ 'ERROR': COLOR_SEQ % RED,
+}
+
+
+class LevelFilter(logging.Filter):
+ """ A filter that selects logging message with specified level """
+ def __init__(self, levels):
+ self._levels = levels
+
+ def filter(self, record):
+ if self._levels:
+ return record.levelname in self._levels
+ return False
+
+
+class MicStreamHandler(logging.StreamHandler):
+ """ A stream handler that print colorized levelname in tty terminal """
+ def __init__(self, stream=None):
+ logging.StreamHandler.__init__(self, stream)
+ msg_fmt = "%(color)s%(levelname)s:%(reset)s %(message)s"
+ self.setFormatter(logging.Formatter(fmt=msg_fmt))
+
+ def _use_color(self):
+ """ Check if to print in color or not """
+ in_emacs = (os.getenv("EMACS") and
+ os.getenv("INSIDE_EMACS", "").endswith(",comint"))
+ return self.stream.isatty() and not in_emacs
+
+ def format(self, record):
+ """ Format the logging record if need color """
+ record.color = record.reset = ""
+ if self._use_color():
+ record.color = COLORS[record.levelname]
+ record.reset = RESET_SEQ
+ return logging.StreamHandler.format(self, record)
+
+
+class RedirectedStderr(object):
+ """ A faked error stream that redirect stderr to a temp file """
+ def __init__(self):
+ self.tmpfile = tempfile.NamedTemporaryFile()
+ self.fderr = None
+ self.value = None
+
+ def __del__(self):
+ self.close()
+
+ def close(self):
+ """ Close the temp file and clear the buffer """
+ try:
+ self.value = None
+ self.tmpfile.close()
+ except OSError:
+ pass
+
+ def truncate(self):
+ """ 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 """
+ self.fderr = os.dup(2)
+ os.dup2(self.tmpfile.fileno(), 2)
+
+ def restore(self):
+ """ Restore the stderr and read the bufferred data """
+ os.dup2(self.fderr, 2)
+ self.fderr = None
+
+ if self.tmpfile:
+ self.tmpfile.seek(0, 0)
+ self.value = self.tmpfile.read()
+
+ def getvalue(self):
+ """ Read the bufferred data """
+ if self.tmpfile:
+ 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
+
+class MicFileHandler(logging.FileHandler):
+ """ This file handler is supposed to catch the stderr output from
+ all modules even 3rd party modules involed, as it redirects
+ the stderr stream to a temp file stream, if logfile assigned,
+ it will flush the record to file stream, else it's a buffer
+ handler; once logfile assigned, the buffer will be flushed
+ """
+ def __init__(self, filename=None, mode='w', encoding=None, capacity=10):
+ # we don't use FileHandler to initialize,
+ # because filename might be expected to None
+ logging.Handler.__init__(self)
+ self.stream = None
+ if filename:
+ self.baseFilename = os.path.abspath(filename)
+ else:
+ self.baseFilename = None
+ self.mode = mode
+ self.encoding = None
+ self.capacity = capacity
+ # buffering the records
+ self.buffer = []
+
+ # set formater locally
+ msg_fmt = "[%(asctime)s] %(message)s"
+ date_fmt = "%m/%d %H:%M:%S %Z"
+ self.setFormatter(logging.Formatter(fmt=msg_fmt, datefmt=date_fmt))
+ self.olderr = sys.stderr
+ self.stderr = RedirectedStderr()
+ self.errmsg = None
+
+ def set_logfile(self, filename, mode='w'):
+ """ Set logfile path to make it possible flush records not-on-fly """
+ self.baseFilename = os.path.abspath(filename)
+ self.mode = mode
+
+ def redirect_stderr(self):
+ """ Start to redirect stderr for catching all error output """
+ self.stderr.redirect()
+
+ def restore_stderr(self):
+ """ Restore stderr stream and log the error messages to both stderr
+ and log file if error messages are not empty
+ """
+ self.stderr.restore()
+ self.errmsg = self.stderr.value
+ if self.errmsg:
+ self.logstderr()
+
+ def logstderr(self):
+ """ Log catched error message from stderr redirector """
+ if not self.errmsg:
+ return
+
+ sys.stdout.write(self.errmsg)
+ sys.stdout.flush()
+
+ record = logging.makeLogRecord({'msg': self.errmsg})
+ self.buffer.append(record)
+
+ # truncate the redirector for the errors is logged
+ self.stderr.truncate()
+ self.errmsg = None
+
+ def emit(self, record):
+ """ Emit the log record to Handler """
+ # if there error message catched, log it first
+ self.errmsg = self.stderr.getvalue()
+ if self.errmsg:
+ self.logstderr()
+
+ # if no logfile assigned, it's a buffer handler
+ if not self.baseFilename:
+ self.buffer.append(record)
+ if len(self.buffer) >= self.capacity:
+ self.buffer = []
+ else:
+ self.flushing(record)
+
+ def flushing(self, record=None):
+ """ Flush buffer and record to logfile """
+ # NOTE: 'flushing' can't be named 'flush' because of 'emit' calling it
+ # set file stream position to SEEK_END(=2)
+ if self.stream:
+ self.stream.seek(0, 2)
+ # if bufferred, flush it
+ if self.buffer:
+ for arecord in self.buffer:
+ logging.FileHandler.emit(self, arecord)
+ self.buffer = []
+ # if recorded, flush it
+ if record:
+ logging.FileHandler.emit(self, record)
+
+ def close(self):
+ """ Close handler after flushing the buffer """
+ # if any left in buffer, flush it
+ if self.stream:
+ self.flushing()
+ logging.FileHandler.close(self)
+
+
+class MicLogger(logging.Logger):
+ """ The MIC logger class, it supports interactive mode, and logs the
+ messages with specified levels tospecified stream, also can catch
+ all error messages including the involved 3rd party modules
+ """
+ def __init__(self, name, level=logging.INFO):
+ logging.Logger.__init__(self, name, level)
+ self.propagate = False
+ self.interactive = True
+ self.logfile = None
+ self._allhandlers = {
+ 'default': logging.StreamHandler(sys.stdout),
+ 'stdout': MicStreamHandler(sys.stdout),
+ 'stderr': MicStreamHandler(sys.stderr),
+ 'logfile': MicFileHandler(),
+ }
+
+ self._allhandlers['default'].addFilter(LevelFilter(['RAWTEXT']))
+ self._allhandlers['default'].setFormatter(
+ logging.Formatter(fmt="%(message)s"))
+ self.addHandler(self._allhandlers['default'])
+
+ self._allhandlers['stdout'].addFilter(LevelFilter(['DEBUG', 'VERBOSE',
+ 'INFO']))
+ self.addHandler(self._allhandlers['stdout'])
+
+ self._allhandlers['stderr'].addFilter(LevelFilter(['WARNING',
+ 'ERROR']))
+ self.addHandler(self._allhandlers['stderr'])
+
+ self.addHandler(self._allhandlers['logfile'])
+
+ def set_logfile(self, filename, mode='w'):
+ """ Set logfile path """
+ self.logfile = filename
+ self._allhandlers['logfile'].set_logfile(self.logfile, mode)
+
+ def enable_logstderr(self):
+ """ Start to log all error messages """
+ if self.logfile:
+ self._allhandlers['logfile'].redirect_stderr()
+
+ def disable_logstderr(self):
+ """ Stop to log all error messages """
+ if self.logfile:
+ self._allhandlers['logfile'].restore_stderr()
+
+ def verbose(self, msg, *args, **kwargs):
+ """ Log a message with level VERBOSE """
+ if self.isEnabledFor(VERBOSE):
+ self._log(VERBOSE, msg, args, **kwargs)
+
+ def raw(self, msg, *args, **kwargs):
+ """ Log a message in raw text format """
+ if self.isEnabledFor(RAWTEXT):
+ self._log(RAWTEXT, msg, args, **kwargs)
+
+ def select(self, msg, optdict, default=None):
+ """ Log a message in interactive mode """
+ if not optdict.keys():
+ return default
+ if default is None:
+ default = optdict.keys()[0]
+ msg += " [%s](%s): " % ('/'.join(optdict.keys()), default)
+ if not self.interactive or self.logfile:
+ reply = default
+ self.raw(msg + reply)
+ else:
+ while True:
+ reply = raw_input(msg).strip()
+ if not reply or reply in optdict:
+ break
+ if not reply:
+ reply = default
+ return optdict[reply]
+
+
+def error(msg):
+ """ Log a message with level ERROR on the MIC logger """
+ LOGGER.error(msg)
+ sys.exit(2)
+
+def warning(msg):
+ """ Log a message with level WARNING on the MIC logger """
+ LOGGER.warning(msg)
+
+def info(msg):
+ """ Log a message with level INFO on the MIC logger """
+ LOGGER.info(msg)
+
+def verbose(msg):
+ """ Log a message with level VERBOSE on the MIC logger """
+ LOGGER.verbose(msg)
+
+def debug(msg):
+ """ Log a message with level DEBUG on the MIC logger """
+ LOGGER.debug(msg)
+
+def raw(msg):
+ """ Log a message on the MIC logger in raw text format"""
+ LOGGER.raw(msg)
+
+def select(msg, optdict, default=None):
+ """ Show an interactive scene in tty terminal and
+ logs them on MIC logger
+ """
+ return LOGGER.select(msg, optdict, default)
+
+def choice(msg, optlist, default=0):
+ """ Give some alternatives to users for answering the question """
+ return LOGGER.select(msg, dict(zip(optlist, optlist)), optlist[default])
+
+def ask(msg, ret=True):
+ """ Ask users to answer 'yes' or 'no' to the question """
+ answers = {'y': True, 'n': False}
+ default = {True: 'y', False: 'n'}[ret]
+ return LOGGER.select(msg, answers, default)
+
+def pause(msg=None):
+ """ Pause for any key """
+ if msg is None:
+ msg = "press ANY KEY to continue ..."
+ raw_input(msg)
+
+def set_logfile(logfile, mode='w'):
+ """ Set logfile path to the MIC logger """
+ LOGGER.set_logfile(logfile, mode)
+
+def set_loglevel(level):
+ """ Set loglevel to the MIC logger """
+ if isinstance(level, basestring):
+ level = logging.getLevelName(level)
+ LOGGER.setLevel(level)
+
+def get_loglevel():
+ """ Get the loglevel of the MIC logger """
+ return logging.getLevelName(LOGGER.level)
+
+def disable_interactive():
+ """ Disable the interactive mode """
+ LOGGER.interactive = False
+
+def enable_interactive():
+ """ Enable the interactive mode """
+ LOGGER.interactive = True
+
+def set_interactive(value):
+ """ Set the interactive mode (for compatibility) """
+ if value:
+ enable_interactive()
+ else:
+ disable_interactive()
+
+def enable_logstderr(fpath=None):
+ """ Start to log all error message on the MIC logger """
+ LOGGER.enable_logstderr()
+
+def disable_logstderr():
+ """ Stop to log all error message on the MIC logger """
+ LOGGER.disable_logstderr()
+
+
+# add two level to the MIC logger: 'VERBOSE', 'RAWTEXT'
+logging.addLevelName(VERBOSE, 'VERBOSE')
+logging.addLevelName(RAWTEXT, 'RAWTEXT')
+# initial the MIC logger
+logging.setLoggerClass(MicLogger)
+LOGGER = logging.getLogger("MIC")
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os, sys
+
+from mic import msger
+from mic import pluginbase
+from mic.conf import configmgr
+from mic.utils import errors
+
+
+__ALL__ = ['PluginMgr', 'pluginmgr']
+
+PLUGIN_TYPES = ["imager", "backend"] # TODO "hook"
+
+
+class PluginMgr(object):
+ plugin_dirs = {}
+
+ # make the manager class as singleton
+ _instance = None
+ def __new__(cls, *args, **kwargs):
+ if not cls._instance:
+ cls._instance = super(PluginMgr, cls).__new__(cls, *args, **kwargs)
+
+ return cls._instance
+
+ def __init__(self):
+ self.plugin_dir = configmgr.common['plugin_dir']
+
+ def append_dirs(self, dirs):
+ for path in dirs:
+ self._add_plugindir(path)
+
+ # load all the plugins AGAIN
+ self._load_all()
+
+ def _add_plugindir(self, path):
+ path = os.path.abspath(os.path.expanduser(path))
+
+ if not os.path.isdir(path):
+ msger.warning("Plugin dir is not a directory or does not exist: %s"\
+ % path)
+ return
+
+ if path not in self.plugin_dirs:
+ self.plugin_dirs[path] = False
+ # the value True/False means "loaded"
+
+ def _load_all(self):
+ for (pdir, loaded) in self.plugin_dirs.iteritems():
+ if loaded: continue
+
+ sys.path.insert(0, pdir)
+ for mod in [x[:-3] for x in os.listdir(pdir) if x.endswith(".py")]:
+ if mod and mod != '__init__':
+ if mod in sys.modules:
+ #self.plugin_dirs[pdir] = True
+ msger.warning("Module %s already exists, skip" % mod)
+ else:
+ try:
+ pymod = __import__(mod)
+ self.plugin_dirs[pdir] = True
+ msger.debug("Plugin module %s:%s imported"\
+ % (mod, pymod.__file__))
+ except ImportError as err:
+ msg = 'Failed to load plugin %s/%s: %s' \
+ % (os.path.basename(pdir), mod, err)
+ msger.verbose(msg)
+
+ del(sys.path[0])
+
+ def get_plugins(self, ptype):
+ """ the return value is dict of name:class pairs """
+
+ if ptype not in PLUGIN_TYPES:
+ raise errors.CreatorError('%s is not valid plugin type' % ptype)
+
+ self._add_plugindir(os.path.join(self.plugin_dir, ptype))
+ self._load_all()
+
+ return pluginbase.get_plugins(ptype)
+
+pluginmgr = PluginMgr()
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+import shutil
+from mic import msger
+from mic.utils import errors
+
+class _Plugin(object):
+ class __metaclass__(type):
+ def __init__(cls, name, bases, attrs):
+ if not hasattr(cls, 'plugins'):
+ cls.plugins = {}
+
+ elif 'mic_plugin_type' in attrs:
+ if attrs['mic_plugin_type'] not in cls.plugins:
+ cls.plugins[attrs['mic_plugin_type']] = {}
+
+ elif hasattr(cls, 'mic_plugin_type') and 'name' in attrs:
+ cls.plugins[cls.mic_plugin_type][attrs['name']] = cls
+
+ def show_plugins(cls):
+ for cls in cls.plugins[cls.mic_plugin_type]:
+ print (cls)
+
+ def get_plugins(cls):
+ return cls.plugins
+
+class ImagerPlugin(_Plugin):
+ mic_plugin_type = "imager"
+
+ @classmethod
+ def check_image_exists(self, destdir, apacking=None,
+ images=(),
+ release=None):
+
+ # if it's a packing file, reset images
+ if apacking:
+ images = [apacking]
+
+ # release option will override images
+ if release is not None:
+ images = [os.path.basename(destdir.rstrip('/'))]
+ destdir = os.path.dirname(destdir.rstrip('/'))
+
+ for name in images:
+ if not name:
+ continue
+
+ image = os.path.join(destdir, name)
+ if not os.path.exists(image):
+ continue
+ if msger.ask("Target image/dir: %s already exists, "
+ "clean up the old files and continue?" % image):
+ if os.path.isdir(image):
+ for path, dirs, files in os.walk(os.path.abspath(image)):
+ for fname in files:
+ fpath = os.path.join(path, fname)
+ if not fpath.endswith('.log'):
+ os.remove(fpath)
+ else:
+ os.unlink(image)
+ else:
+ raise errors.Abort("Canceled")
+
+ def do_create(self):
+ pass
+
+ def do_chroot(self):
+ pass
+
+class BackendPlugin(_Plugin):
+ mic_plugin_type="backend"
+
+ def addRepository(self):
+ pass
+
+def get_plugins(typen):
+ ps = ImagerPlugin.get_plugins()
+ if typen in ps:
+ return ps[typen]
+ else:
+ return None
+
+__all__ = ['ImagerPlugin', 'BackendPlugin', 'get_plugins']
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2009, 2010, 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+import sys
+import glob
+import re
+import shutil
+import subprocess
+import ctypes
+
+from mic import bootstrap, msger
+from mic.conf import configmgr
+from mic.utils import errors, proxy
+from mic.utils.fs_related import find_binary_path, makedirs
+from mic.chroot import setup_chrootenv, cleanup_chrootenv, ELF_arch
+
+from mic.plugin import pluginmgr
+
+_libc = ctypes.cdll.LoadLibrary(None)
+_errno = ctypes.c_int.in_dll(_libc, "errno")
+_libc.personality.argtypes = [ctypes.c_ulong]
+_libc.personality.restype = ctypes.c_int
+_libc.unshare.argtypes = [ctypes.c_int,]
+_libc.unshare.restype = ctypes.c_int
+
+expath = lambda p: os.path.abspath(os.path.expanduser(p))
+
+PER_LINUX32=0x0008
+PER_LINUX=0x0000
+personality_defs = {
+ 'x86_64': PER_LINUX, 'ppc64': PER_LINUX, 'sparc64': PER_LINUX,
+ 'i386': PER_LINUX32, 'i586': PER_LINUX32, 'i686': PER_LINUX32,
+ 'ppc': PER_LINUX32, 'sparc': PER_LINUX32, 'sparcv9': PER_LINUX32,
+ 'ia64' : PER_LINUX, 'alpha' : PER_LINUX,
+ 's390' : PER_LINUX32, 's390x' : PER_LINUX,
+}
+
+def condPersonality(per=None):
+ if per is None or per in ('noarch',):
+ return
+ if personality_defs.get(per, None) is None:
+ return
+ res = _libc.personality(personality_defs[per])
+ if res == -1:
+ raise OSError(_errno.value, os.strerror(_errno.value))
+
+def inbootstrap():
+ if os.path.exists(os.path.join("/", ".chroot.lock")):
+ return True
+ return (os.stat("/").st_ino != 2)
+
+def bootstrap_mic(argv=None):
+ def mychroot():
+ os.chroot(rootdir)
+ os.chdir(cwd)
+
+ # by default, sys.argv is used to run mic in bootstrap
+ if not argv:
+ argv = sys.argv
+ if argv[0] not in ('/usr/bin/mic', 'mic'):
+ argv[0] = '/usr/bin/mic'
+
+ cropts = configmgr.create
+ bsopts = configmgr.bootstrap
+ distro = bsopts['distro_name'].lower()
+
+ rootdir = bsopts['rootdir']
+ pkglist = bsopts['packages']
+ cwd = os.getcwd()
+
+ # create bootstrap and run mic in bootstrap
+ bsenv = bootstrap.Bootstrap(rootdir, distro, cropts['arch'])
+ bsenv.logfile = cropts['logfile']
+ # rootdir is regenerated as a temp dir
+ rootdir = bsenv.rootdir
+
+ if 'optional' in bsopts:
+ optlist = bsopts['optional']
+ else:
+ optlist = []
+
+ try:
+ msger.info("Creating %s bootstrap ..." % distro)
+ bsenv.create(cropts['repomd'], pkglist, optlist)
+
+ # bootstrap is relocated under "bootstrap"
+ if os.path.exists(os.path.join(rootdir, "bootstrap")):
+ rootdir = os.path.join(rootdir, "bootstrap")
+
+ bsenv.dirsetup(rootdir)
+ 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)):
+ safecopy(configmgr._ksconf, rootdir)
+
+ msger.info("Start mic in bootstrap: %s\n" % rootdir)
+ bsarch = ELF_arch(rootdir)
+ if bsarch in personality_defs:
+ condPersonality(bsarch)
+ bindmounts = get_bindmounts(cropts)
+ ret = bsenv.run(argv, cwd, rootdir, bindmounts)
+
+ except errors.BootstrapError as err:
+ raise errors.CreatorError("Failed to download/install bootstrap package " \
+ "or the package is in bad format: %s" % err)
+ except RuntimeError as err:
+ #change exception type but keep the trace back
+ value,tb = sys.exc_info()[1:]
+ raise errors.CreatorError((value,tb))
+ else:
+ sys.exit(ret)
+ finally:
+ bsenv.cleanup()
+
+def get_bindmounts(cropts):
+ binddirs = [
+ os.getcwd(),
+ cropts['tmpdir'],
+ cropts['cachedir'],
+ cropts['outdir'],
+ cropts['local_pkgs_path'],
+ ]
+ bindfiles = [
+ cropts['logfile'],
+ configmgr._ksconf,
+ ]
+
+ 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)))
+ bindlist = sorted(set(bindlist))
+ bindmounts = ';'.join(bindlist)
+ return bindmounts
+
+
+def get_mic_binpath():
+ fp = None
+ try:
+ import pkg_resources # depends on 'setuptools'
+ dist = pkg_resources.get_distribution('mic')
+ # the real script is under EGG_INFO/scripts
+ if dist.has_metadata('scripts/mic'):
+ fp = os.path.join(dist.egg_info, "scripts/mic")
+ except ImportError:
+ pass
+ except pkg_resources.DistributionNotFound:
+ pass
+
+
+ if fp:
+ return fp
+
+ # not found script if 'flat' egg installed
+ try:
+ return find_binary_path('mic')
+ except errors.CreatorError:
+ raise errors.BootstrapError("Can't find mic binary in host OS")
+
+
+def get_mic_modpath():
+ try:
+ import mic
+ except ImportError:
+ raise errors.BootstrapError("Can't find mic module in host OS")
+ path = os.path.abspath(mic.__file__)
+ return os.path.dirname(path)
+
+def get_mic_libpath():
+ return os.getenv("MIC_LIBRARY_PATH", "/usr/lib/mic")
+
+# the hard code path is prepared for bootstrap
+def sync_mic(bootstrap, binpth = '/usr/bin/mic',
+ libpth='/usr/lib',
+ plugin='/usr/lib/mic/plugins',
+ pylib = '/usr/lib/python2.7/site-packages',
+ conf = '/etc/mic/mic.conf'):
+ _path = lambda p: os.path.join(bootstrap, p.lstrip('/'))
+
+ micpaths = {
+ 'binpth': get_mic_binpath(),
+ 'libpth': get_mic_libpath(),
+ 'plugin': plugin,
+ 'pylib': get_mic_modpath(),
+ 'conf': '/etc/mic/mic.conf',
+ }
+
+ if not os.path.exists(_path(pylib)):
+ pyptn = '/usr/lib/python?.?/site-packages'
+ pylibs = glob.glob(_path(pyptn))
+ if pylibs:
+ pylib = pylibs[0].replace(bootstrap, '')
+ else:
+ raise errors.BootstrapError("Can't find python site dir in: %s" %
+ bootstrap)
+
+ for key, value in micpaths.items():
+ try:
+ safecopy(value, _path(eval(key)), False, ["*.pyc", "*.pyo"])
+ except (OSError, IOError) as err:
+ raise errors.BootstrapError(err)
+
+ # auto select backend
+ conf_str = file(_path(conf)).read()
+ conf_str = re.sub("pkgmgr\s*=\s*.*", "pkgmgr=auto", conf_str)
+ with open(_path(conf), 'w') as wf:
+ wf.write(conf_str)
+
+ # chmod +x /usr/bin/mic
+ os.chmod(_path(binpth), 0o777)
+
+ # correct python interpreter
+ mic_cont = file(_path(binpth)).read()
+ mic_cont = "#!/usr/bin/python\n" + mic_cont
+ with open(_path(binpth), 'w') as wf:
+ wf.write(mic_cont)
+
+
+def safecopy(src, dst, symlinks=False, ignore_ptns=()):
+ if os.path.isdir(src):
+ if os.path.isdir(dst):
+ dst = os.path.join(dst, os.path.basename(src))
+ if os.path.exists(dst):
+ shutil.rmtree(dst, ignore_errors=True)
+
+ src = src.rstrip('/')
+ # check common prefix to ignore copying itself
+ if dst.startswith(src + '/'):
+ ignore_ptns = list(ignore_ptns) + [ os.path.basename(src) ]
+
+ ignores = shutil.ignore_patterns(*ignore_ptns)
+ try:
+ shutil.copytree(src, dst, symlinks, ignores)
+ except (OSError, IOError):
+ shutil.rmtree(dst, ignore_errors=True)
+ raise
+ else:
+ if not os.path.isdir(dst):
+ makedirs(os.path.dirname(dst))
+
+ shutil.copy2(src, dst)
+
+def prepare_create(args):
+ """
+ Usage:
+ ${name} ${cmd_name} <ksfile> [OPTS]
+
+ ${cmd_option_list}
+ """
+
+ if args is None:
+ raise errors.Usage("Invalid arguments.")
+
+ creatoropts = configmgr.create
+ ksconf = args.ksfile
+
+ if creatoropts['runtime'] == 'bootstrap':
+ configmgr._ksconf = ksconf
+ bootstrap_mic()
+
+ recording_pkgs = []
+ if len(creatoropts['record_pkgs']) > 0:
+ recording_pkgs = creatoropts['record_pkgs']
+
+ if creatoropts['release'] is not None:
+ if 'name' not in recording_pkgs:
+ recording_pkgs.append('name')
+ if 'vcs' not in recording_pkgs:
+ recording_pkgs.append('vcs')
+
+ configmgr._ksconf = ksconf
+
+ # try to find the pkgmgr
+ pkgmgr = None
+ backends = pluginmgr.get_plugins('backend')
+ if 'auto' == creatoropts['pkgmgr']:
+ for key in configmgr.prefer_backends:
+ if key in backends:
+ pkgmgr = backends[key]
+ break
+ else:
+ for key in backends.keys():
+ if key == creatoropts['pkgmgr']:
+ pkgmgr = backends[key]
+ break
+
+ if not pkgmgr:
+ raise errors.CreatorError("Can't find backend: %s, "
+ "available choices: %s" %
+ (creatoropts['pkgmgr'],
+ ','.join(backends.keys())))
+ return creatoropts, pkgmgr, recording_pkgs
+
--- /dev/null
+#
+# Copyright (c) 2011~2013 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+""" Collection of all error class """
+
+class CreatorError(Exception):
+ """ Based class for all mic creator errors """
+ keyword = None
+
+ def __init__(self, msg):
+ Exception.__init__(self)
+ self.msg = msg
+
+ def __str__(self):
+ if isinstance(self.msg, unicode):
+ self.msg = self.msg.encode('utf-8', 'ignore')
+ else:
+ self.msg = str(self.msg)
+ return self.msg
+
+ def __repr__(self):
+ if not hasattr(self, 'keyword') or not self.keyword:
+ self.keyword = self.__class__.__name__
+ return "<%s> %s" % (self.keyword, str(self))
+
+class Usage(CreatorError):
+ """ Error class for Usage """
+ pass
+
+class Abort(CreatorError):
+ """ Error class for Abort """
+ pass
+
+class ConfigError(CreatorError):
+ """ Error class for Config file """
+ keyword = 'Config'
+
+class KsError(CreatorError):
+ """ Error class for Kickstart module """
+ keyword = 'Kickstart'
+
+class RepoError(CreatorError):
+ """ Error class for Repository related """
+ keyword = 'Repository'
+
+class RpmError(CreatorError):
+ """ Error class for RPM related """
+ keyword = 'RPM'
+
+class MountError(CreatorError):
+ """ Error class for Mount related """
+ keyword = 'Mount'
+
+class SnapshotError(CreatorError):
+ """ Error class for Snapshot related """
+ keyword = 'Snapshot'
+
+class SquashfsError(CreatorError):
+ """ Error class for Squashfs related """
+ keyword = 'Squashfs'
+
+class VdfsError(CreatorError):
+ """ Error class for Vdfs related """
+ keyword = 'vdfs'
+
+class BootstrapError(CreatorError):
+ """ Error class for Bootstrap related """
+ keyword = 'Bootstrap'
+
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2007, Red Hat, Inc.
+# Copyright (c) 2009, 2010, 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+from __future__ import with_statement
+import os
+import re
+import sys
+import errno
+import stat
+import random
+import string
+import time
+import uuid
+
+from mic import msger
+from mic.utils import runner
+from mic.utils.errors import *
+
+
+def find_binary_inchroot(binary, chroot):
+ paths = ["/usr/sbin",
+ "/usr/bin",
+ "/sbin",
+ "/bin"
+ ]
+
+ for path in paths:
+ bin_path = "%s/%s" % (path, binary)
+ if os.path.exists("%s/%s" % (chroot, bin_path)):
+ return bin_path
+ return None
+
+def find_binary_path(binary):
+ if os.environ.has_key("PATH"):
+ paths = os.environ["PATH"].split(":")
+ else:
+ paths = []
+ if os.environ.has_key("HOME"):
+ paths += [os.environ["HOME"] + "/bin"]
+ paths += ["/usr/local/sbin", "/usr/local/bin", "/usr/sbin", "/usr/bin", "/sbin", "/bin"]
+
+ for path in paths:
+ bin_path = "%s/%s" % (path, binary)
+ if os.path.exists(bin_path):
+ return bin_path
+ raise CreatorError("Command '%s' is not available." % binary)
+
+def makedirs(dirname):
+ """A version of os.makedirs() that doesn't throw an
+ exception if the leaf directory already exists.
+ """
+ try:
+ os.makedirs(dirname)
+ except OSError as err:
+ if err.errno != errno.EEXIST:
+ raise
+
+def mkvdfs(in_img, out_img, fsoptions):
+ """ This function is incomplete. """
+ fullpathmkvdfs = find_binary_path("mkfs.vdfs")
+# args = fullpathmkvdfs + " -i -r "+ in_img + " -z 1024M -s " + out_img
+ args = fullpathmkvdfs + " " + fsoptions + " -r " + in_img + " " + out_img
+ msger.verbose("vdfs args: %s" % args)
+ runner.show("%s --help" % fullpathmkvdfs)
+# if not sys.stdout.isatty():
+# args.append("-no-progress")
+# runner.show("%s --help" % fullpathmkvdfs)
+ ret = runner.show(args)
+ if ret != 0:
+ runner.show ("vdfs error")
+ raise VdfsError("' %s' exited with error (%d)" % (args, ret))
+
+def mksquashfs(in_img, out_img):
+ fullpathmksquashfs = find_binary_path("mksquashfs")
+ args = [fullpathmksquashfs, in_img, out_img]
+
+ if not sys.stdout.isatty():
+ args.append("-no-progress")
+
+ ret = runner.show(args)
+ if ret != 0:
+ raise SquashfsError("'%s' exited with error (%d)" % (' '.join(args), ret))
+
+def resize2fs(fs, size):
+ resize2fs = find_binary_path("resize2fs")
+ if size == 0:
+ # it means to minimalize it
+ return runner.show([resize2fs, '-M', fs])
+ else:
+ return runner.show([resize2fs, fs, "%sK" % (size / 1024,)])
+
+class BindChrootMount:
+ """Represents a bind mount of a directory into a chroot."""
+ def __init__(self, src, chroot, dest = None, option = None):
+ self.root = os.path.abspath(os.path.expanduser(chroot))
+ self.mount_option = option
+
+ self.orig_src = self.src = src
+ if os.path.islink(src):
+ self.src = os.readlink(src)
+ if not self.src.startswith('/'):
+ self.src = os.path.abspath(os.path.join(os.path.dirname(src),
+ self.src))
+
+ if not dest:
+ dest = self.src
+ self.dest = os.path.join(self.root, dest.lstrip('/'))
+
+ self.mounted = False
+ self.mountcmd = find_binary_path("mount")
+ self.umountcmd = find_binary_path("umount")
+
+ def ismounted(self):
+ with open('/proc/mounts') as f:
+ for line in f:
+ if line.split()[1] == os.path.abspath(self.dest):
+ return True
+
+ return False
+
+ def mount(self):
+ if self.mounted or self.ismounted():
+ return
+
+ try:
+ makedirs(self.dest)
+ except OSError as err:
+ if err.errno == errno.ENOSPC:
+ msger.warning("No space left on device '%s'" % err.filename)
+ return
+
+ if self.mount_option:
+ cmdline = [self.mountcmd, "-o" ,"bind", "-o", "%s" % \
+ self.mount_option, self.src, self.dest]
+ else:
+ cmdline = [self.mountcmd, "-o" ,"bind", self.src, self.dest]
+ rc, errout = runner.runtool(cmdline, catch=2)
+ if rc != 0:
+ raise MountError("Bind-mounting '%s' to '%s' failed: %s" %
+ (self.src, self.dest, errout))
+
+ self.mounted = True
+ if os.path.islink(self.orig_src):
+ dest = os.path.join(self.root, self.orig_src.lstrip('/'))
+ if not os.path.exists(dest):
+ os.symlink(self.src, dest)
+
+ def unmount(self):
+ if self.mounted or self.ismounted():
+ runner.show([self.umountcmd, "-l", self.dest])
+ self.mounted = False
+
+class LoopbackMount:
+ """LoopbackMount compatibility layer for old API"""
+ def __init__(self, lofile, mountdir, fstype = None):
+ self.diskmount = DiskMount(LoopbackDisk(lofile,size = 0),mountdir,fstype,rmmountdir = True)
+ self.losetup = False
+ self.losetupcmd = find_binary_path("losetup")
+
+ def cleanup(self):
+ self.diskmount.cleanup()
+
+ def unmount(self):
+ self.diskmount.unmount()
+
+ def lounsetup(self):
+ if self.losetup:
+ runner.show([self.losetupcmd, "-d", self.loopdev])
+ self.losetup = False
+ self.loopdev = None
+
+ def loopsetup(self):
+ if self.losetup:
+ return
+
+ self.loopdev = get_loop_device(self.losetupcmd, self.lofile)
+ self.losetup = True
+
+ def mount(self):
+ self.diskmount.mount()
+
+class SparseLoopbackMount(LoopbackMount):
+ """SparseLoopbackMount compatibility layer for old API"""
+ def __init__(self, lofile, mountdir, size, fstype = None):
+ self.diskmount = DiskMount(SparseLoopbackDisk(lofile,size),mountdir,fstype,rmmountdir = True)
+
+ def expand(self, create = False, size = None):
+ self.diskmount.disk.expand(create, size)
+
+ def truncate(self, size = None):
+ self.diskmount.disk.truncate(size)
+
+ def create(self):
+ self.diskmount.disk.create()
+
+class SparseExtLoopbackMount(SparseLoopbackMount):
+ """SparseExtLoopbackMount compatibility layer for old API"""
+ def __init__(self, lofile, mountdir, size, fstype, blocksize, fslabel):
+ self.diskmount = ExtDiskMount(SparseLoopbackDisk(lofile,size), mountdir, fstype, blocksize, fslabel, rmmountdir = True)
+
+
+ def __format_filesystem(self):
+ self.diskmount.__format_filesystem()
+
+ def create(self):
+ self.diskmount.disk.create()
+
+ def resize(self, size = None):
+ return self.diskmount.__resize_filesystem(size)
+
+ def mount(self):
+ self.diskmount.mount()
+
+ def __fsck(self):
+ self.extdiskmount.__fsck()
+
+ def __get_size_from_filesystem(self):
+ return self.diskmount.__get_size_from_filesystem()
+
+ def __resize_to_minimal(self):
+ return self.diskmount.__resize_to_minimal()
+
+ def resparse(self, size = None):
+ return self.diskmount.resparse(size)
+
+class Disk:
+ """Generic base object for a disk
+
+ The 'create' method must make the disk visible as a block device - eg
+ by calling losetup. For RawDisk, this is obviously a no-op. The 'cleanup'
+ method must undo the 'create' operation.
+ """
+ def __init__(self, size, device = None):
+ self._device = device
+ self._size = size
+
+ def create(self):
+ pass
+
+ def cleanup(self):
+ pass
+
+ def get_device(self):
+ return self._device
+ def set_device(self, path):
+ self._device = path
+ device = property(get_device, set_device)
+
+ def get_size(self):
+ return self._size
+ size = property(get_size)
+
+
+class RawDisk(Disk):
+ """A Disk backed by a block device.
+ Note that create() is a no-op.
+ """
+ def __init__(self, size, device):
+ Disk.__init__(self, size, device)
+
+ def fixed(self):
+ return True
+
+ def exists(self):
+ return True
+
+class LoopbackDisk(Disk):
+ """A Disk backed by a file via the loop module."""
+ def __init__(self, lofile, size):
+ Disk.__init__(self, size)
+ self.lofile = lofile
+ self.losetupcmd = find_binary_path("losetup")
+
+ def fixed(self):
+ return False
+
+ def exists(self):
+ return os.path.exists(self.lofile)
+
+ def create(self):
+ if self.device is not None:
+ return
+
+ self.device = get_loop_device(self.losetupcmd, self.lofile)
+
+ def cleanup(self):
+ if self.device is None:
+ return
+ msger.debug("Losetup remove %s" % self.device)
+ 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):
+ LoopbackDisk.__init__(self, lofile, size)
+
+ def expand(self, create = False, size = None):
+ flags = os.O_WRONLY
+ if create:
+ flags |= os.O_CREAT
+ if not os.path.exists(self.lofile):
+ makedirs(os.path.dirname(self.lofile))
+
+ if size is None:
+ size = self.size
+
+ msger.debug("Extending sparse file %s to %d" % (self.lofile, size))
+ if create:
+ fd = os.open(self.lofile, flags, 0o644)
+ else:
+ fd = os.open(self.lofile, flags)
+
+ if size <= 0:
+ size = 1
+ try:
+ os.ftruncate(fd, size)
+ except:
+ # may be limited by 2G in 32bit env
+ os.ftruncate(fd, 2**31)
+
+ os.close(fd)
+
+ def truncate(self, size = None):
+ if size is None:
+ size = self.size
+
+ msger.debug("Truncating sparse file %s to %d" % (self.lofile, size))
+ fd = os.open(self.lofile, os.O_WRONLY)
+ os.ftruncate(fd, size)
+ os.close(fd)
+
+ def create(self):
+ if self.device is not None:
+ return
+
+ self.expand(create = True)
+ LoopbackDisk.create(self)
+
+class Mount(object):
+ """A generic base class to deal with mounting things."""
+ def __init__(self, mountdir):
+ self.mountdir = mountdir
+
+ def cleanup(self):
+ self.unmount()
+
+ def mount(self, options = None):
+ pass
+
+ def unmount(self):
+ pass
+
+class DiskMount(Mount):
+ """A Mount object that handles mounting of a Disk."""
+ def __init__(self, disk, mountdir, fstype = None, rmmountdir = True):
+ Mount.__init__(self, mountdir)
+
+ self.disk = disk
+ self.fstype = fstype
+ self.rmmountdir = rmmountdir
+
+ self.mounted = False
+ self.rmdir = False
+ if fstype:
+ self.mkfscmd = find_binary_path("mkfs." + self.fstype)
+ else:
+ self.mkfscmd = None
+ self.mountcmd = find_binary_path("mount")
+ self.umountcmd = find_binary_path("umount")
+
+ def cleanup(self):
+ Mount.cleanup(self)
+ self.disk.cleanup()
+
+ def unmount(self):
+ if self.mounted:
+ msger.debug("Unmounting directory %s" % self.mountdir)
+ runner.quiet('sync') # sync the data on this mount point
+ rc = runner.show([self.umountcmd, "-l", self.mountdir])
+ if rc == 0:
+ self.mounted = False
+ else:
+ raise MountError("Failed to umount %s" % self.mountdir)
+ if self.rmdir and not self.mounted:
+ try:
+ os.rmdir(self.mountdir)
+ except OSError as e:
+ pass
+ self.rmdir = False
+
+
+ def __create(self):
+ self.disk.create()
+
+
+ def mount(self, options = None):
+ if self.mounted:
+ return
+
+ if not os.path.isdir(self.mountdir):
+ msger.debug("Creating mount point %s" % self.mountdir)
+ os.makedirs(self.mountdir)
+ self.rmdir = self.rmmountdir
+
+ self.__create()
+
+ msger.debug("Mounting %s at %s" % (self.disk.device, self.mountdir))
+ if options:
+ args = [ self.mountcmd, "-o", options, self.disk.device, self.mountdir ]
+ else:
+ args = [ self.mountcmd, self.disk.device, self.mountdir ]
+ if self.fstype:
+ args.extend(["-t", self.fstype])
+
+ rc = runner.show(args)
+ if rc != 0:
+ raise MountError("Failed to mount '%s' to '%s' with command '%s'. Retval: %s" %
+ (self.disk.device, self.mountdir, " ".join(args), rc))
+
+ self.mounted = True
+
+class F2fsDiskMount(DiskMount):
+ """A DiskMount object that is able to format/resize f2fs filesystems."""
+ def __init__(self, disk, mountdir, fstype, blocksize, fslabel, rmmountdir=True, skipformat = False, fsopts = None, fsuuid=None):
+ self.__check_f2fs()
+ DiskMount.__init__(self, disk, mountdir, fstype, rmmountdir)
+ self.blocksize = blocksize
+ self.fslabel = fslabel.replace("/", "")
+ self.uuid = fsuuid or None
+ self.skipformat = skipformat
+ self.fsopts = fsopts
+ self.__f2fsopts = None
+ self.blkidcmd = find_binary_path("blkid")
+ self.dumpe2fs = find_binary_path("dump." + self.fstype)
+ self.fsckcmd = find_binary_path("fsck." + self.fstype)
+ self.resizecmd = find_binary_path("resize." + self.fstype)
+
+ def __get_f2fsopts(self):
+ return self.__f2f2opts
+
+ def __set_f2fsopts(self, val):
+ if val is None:
+ self.__f2fsopts = None
+ else:
+ self.__f2fsopts = val
+ f2fsopts = property(__get_f2fsopts, __set_f2fsopts)
+
+ def __check_f2fs(self):
+ found = False
+ """ Need to load f2fs module to mount it """
+ load_module("f2fs")
+ for line in open("/proc/filesystems").xreadlines():
+ if line.find("f2fs") > -1:
+ found = True
+ break
+ if not found:
+ raise MountError("Your system can't mount f2fs filesystem, please make sure your kernel has f2fs support and the module f2fs.ko has been loaded.")
+
+ def __parse_field(self, output, field):
+ for line in output.split(" "):
+ if line.startswith(field + "="):
+ return line[len(field) + 1:].strip().replace("\"", "")
+
+ raise KeyError("Failed to find field '%s' in output" % field)
+
+ def __format_filesystem(self):
+ if self.skipformat:
+ msger.debug("Skip filesystem format.")
+ return
+
+ msger.verbose("Formating %s filesystem on %s" % (self.fstype, self.disk.device))
+
+ cmdlist = [self.mkfscmd, "-l", self.fslabel]
+ if self.__f2fsopts:
+ cmdlist.extend(self.__f2fsopts.split())
+ cmdlist.extend([self.disk.device])
+
+ rc, errout = runner.runtool(cmdlist, catch=2)
+ if rc != 0:
+ raise MountError("Error creating %s filesystem on disk %s:\n%s" %
+ (self.fstype, self.disk.device, errout))
+
+ self.uuid = self.__parse_field(runner.outs([self.blkidcmd, self.disk.device]), "UUID")
+
+ def __resize_filesystem(self, size = None):
+ msger.info("Resizing filesystem ...")
+ current_size = os.stat(self.disk.lofile)[stat.ST_SIZE]
+
+ if size is None:
+ size = self.disk.size
+
+ if size == current_size:
+ return
+
+ if size > current_size:
+ self.disk.expand(size=size)
+
+ self.__fsck()
+
+ return size
+
+ def __create(self):
+ resize = False
+ if not self.disk.fixed() and self.disk.exists():
+ resize = True
+
+ self.disk.create()
+
+ if resize:
+ self.__resize_filesystem()
+ else:
+ self.__format_filesystem()
+
+ 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):
+ msger.info("Checking filesystem %s" % self.disk.lofile)
+ runner.quiet([self.fsckcmd, self.disk.lofile])
+
+ def __get_size_from_filesystem(self):
+ return self.disk.size
+
+ def __resize_to_minimal(self):
+ msger.info("Resizing filesystem to minimal ...")
+ self.__fsck()
+
+ return self.__get_size_from_filesystem()
+
+ def resparse(self, size = None):
+ self.cleanup()
+ if size == 0:
+ minsize = 0
+ else:
+ minsize = self.__resize_to_minimal()
+ self.disk.truncate(minsize)
+ self.__resize_filesystem(size)
+ return minsize
+
+class ExtDiskMount(DiskMount):
+ """A DiskMount object that is able to format/resize ext[23] filesystems."""
+ def __init__(self, disk, mountdir, fstype, blocksize, fslabel, rmmountdir=True, skipformat = False, fsopts = None, fsuuid=None):
+ DiskMount.__init__(self, disk, mountdir, fstype, rmmountdir)
+ self.blocksize = blocksize
+ self.fslabel = fslabel.replace("/", "")
+ self.uuid = fsuuid or str(uuid.uuid4())
+ self.skipformat = skipformat
+ self.fsopts = fsopts
+ 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 + ":"):
+ return line[len(field) + 1:].strip()
+
+ raise KeyError("Failed to find field '%s' in output" % field)
+
+ def __format_filesystem(self):
+ if self.skipformat:
+ msger.debug("Skip filesystem format.")
+ return
+
+ 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())
+ cmdlist.extend([self.disk.device])
+
+ rc, errout = runner.runtool(cmdlist, catch=2)
+ if rc != 0:
+ raise MountError("Error creating %s filesystem on disk %s:\n%s" %
+ (self.fstype, self.disk.device, errout))
+
+ 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])
+
+ def __resize_filesystem(self, size = None):
+ msger.info("Resizing filesystem ...")
+ current_size = os.stat(self.disk.lofile)[stat.ST_SIZE]
+
+ if size is None:
+ size = self.disk.size
+
+ if size == current_size:
+ return
+
+ if size > current_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 %d " % (self.disk.lofile, size))
+
+ return size
+
+ def __create(self):
+ resize = False
+ if not self.disk.fixed() and self.disk.exists():
+ resize = True
+
+ self.disk.create()
+
+ if resize:
+ self.__resize_filesystem()
+ else:
+ self.__format_filesystem()
+
+ 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):
+ msger.info("Checking filesystem %s" % self.disk.lofile)
+ runner.quiet(["/sbin/e2fsck", "-f", "-y", self.disk.lofile])
+
+ def __get_size_from_filesystem(self):
+ return int(self.__parse_field(runner.outs([self.dumpe2fs, '-h', self.disk.lofile]),
+ "Block count")) * self.blocksize
+
+ def __resize_to_minimal(self):
+ msger.info("Resizing filesystem to minimal ...")
+ self.__fsck()
+ resize2fs(self.disk.lofile, 0)
+ return self.__get_size_from_filesystem()
+
+ def resparse(self, size = None):
+ self.cleanup()
+ if size == 0:
+ minsize = 0
+ else:
+ minsize = self.__resize_to_minimal()
+ self.disk.truncate(minsize)
+
+ self.__resize_filesystem(size)
+ return minsize
+
+class VfatDiskMount(DiskMount):
+ """A DiskMount object that is able to format vfat/msdos filesystems."""
+ def __init__(self, disk, mountdir, fstype, blocksize, fslabel, rmmountdir=True, skipformat = False, fsopts = None, fsuuid = None):
+ DiskMount.__init__(self, disk, mountdir, fstype, rmmountdir)
+ self.blocksize = blocksize
+ self.fslabel = fslabel.replace("/", "")
+ rand1 = random.randint(0, 2**16 - 1)
+ rand2 = random.randint(0, 2**16 - 1)
+ self.uuid = fsuuid or "%04X-%04X" % (rand1, rand2)
+ self.skipformat = skipformat
+ self.fsopts = fsopts
+ self.fsckcmd = find_binary_path("fsck." + self.fstype)
+
+ def __format_filesystem(self):
+ if self.skipformat:
+ msger.debug("Skip filesystem format.")
+ return
+
+ msger.verbose("Formating %s filesystem on %s" % (self.fstype, self.disk.device))
+ rc = runner.show([self.mkfscmd, "-n", self.fslabel,
+ "-i", self.uuid.replace("-", ""), self.disk.device])
+ if rc != 0:
+ raise MountError("Error creating %s filesystem on disk %s" % (self.fstype,self.disk.device))
+
+ msger.verbose("Tuning filesystem on %s" % self.disk.device)
+
+ def __resize_filesystem(self, size = None):
+ current_size = os.stat(self.disk.lofile)[stat.ST_SIZE]
+
+ if size is None:
+ size = self.disk.size
+
+ if size == current_size:
+ return
+
+ if size > current_size:
+ self.disk.expand(size=size)
+
+ self.__fsck()
+
+ #resize2fs(self.disk.lofile, size)
+ return size
+
+ def __create(self):
+ resize = False
+ if not self.disk.fixed() and self.disk.exists():
+ resize = True
+
+ self.disk.create()
+
+ if resize:
+ self.__resize_filesystem()
+ else:
+ self.__format_filesystem()
+
+ 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):
+ msger.debug("Checking filesystem %s" % self.disk.lofile)
+ runner.show([self.fsckcmd, "-y", self.disk.lofile])
+
+ def __get_size_from_filesystem(self):
+ return self.disk.size
+
+ def __resize_to_minimal(self):
+ 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()
+ return top
+
+ def resparse(self, size = None):
+ self.cleanup()
+ minsize = self.__resize_to_minimal()
+ self.disk.truncate(minsize)
+ self.__resize_filesystem(size)
+ return minsize
+
+class BtrfsDiskMount(DiskMount):
+ """A DiskMount object that is able to format/resize btrfs filesystems."""
+ def __init__(self, disk, mountdir, fstype, blocksize, fslabel, rmmountdir=True, skipformat = False, fsopts = None, fsuuid = None):
+ self.__check_btrfs()
+ DiskMount.__init__(self, disk, mountdir, fstype, rmmountdir)
+ self.blocksize = blocksize
+ self.fslabel = fslabel.replace("/", "")
+ self.uuid = fsuuid or None
+ self.skipformat = skipformat
+ self.fsopts = fsopts
+ self.blkidcmd = find_binary_path("blkid")
+ self.btrfsckcmd = find_binary_path("btrfsck")
+
+ def __check_btrfs(self):
+ found = False
+ """ Need to load btrfs module to mount it """
+ load_module("btrfs")
+ for line in open("/proc/filesystems").xreadlines():
+ if line.find("btrfs") > -1:
+ found = True
+ break
+ if not found:
+ raise MountError("Your system can't mount btrfs filesystem, please make sure your kernel has btrfs support and the module btrfs.ko has been loaded.")
+
+ # disable selinux, selinux will block write
+ if os.path.exists("/usr/sbin/setenforce"):
+ runner.show(["/usr/sbin/setenforce", "0"])
+
+ def __parse_field(self, output, field):
+ for line in output.split(" "):
+ if line.startswith(field + "="):
+ return line[len(field) + 1:].strip().replace("\"", "")
+
+ raise KeyError("Failed to find field '%s' in output" % field)
+
+ def __format_filesystem(self):
+ if self.skipformat:
+ msger.debug("Skip filesystem format.")
+ return
+
+ msger.verbose("Formating %s filesystem on %s" % (self.fstype, self.disk.device))
+ rc = runner.show([self.mkfscmd, "-L", self.fslabel, "-m", "single", self.disk.device])
+ if rc != 0:
+ raise MountError("Error creating %s filesystem on disk %s" % (self.fstype,self.disk.device))
+
+ self.uuid = self.__parse_field(runner.outs([self.blkidcmd, self.disk.device]), "UUID")
+
+ def __resize_filesystem(self, size = None):
+ current_size = os.stat(self.disk.lofile)[stat.ST_SIZE]
+
+ if size is None:
+ size = self.disk.size
+
+ if size == current_size:
+ return
+
+ if size > current_size:
+ self.disk.expand(size=size)
+
+ self.__fsck()
+ return size
+
+ def __create(self):
+ resize = False
+ if not self.disk.fixed() and self.disk.exists():
+ resize = True
+
+ self.disk.create()
+
+ if resize:
+ self.__resize_filesystem()
+ else:
+ self.__format_filesystem()
+
+ 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):
+ msger.debug("Checking filesystem %s" % self.disk.lofile)
+ runner.quiet([self.btrfsckcmd, self.disk.lofile])
+
+ def __get_size_from_filesystem(self):
+ return self.disk.size
+
+ def __resize_to_minimal(self):
+ self.__fsck()
+
+ return self.__get_size_from_filesystem()
+
+ def resparse(self, size = None):
+ self.cleanup()
+ minsize = self.__resize_to_minimal()
+ self.disk.truncate(minsize)
+ self.__resize_filesystem(size)
+ return minsize
+
+class DeviceMapperSnapshot(object):
+ def __init__(self, imgloop, cowloop):
+ self.imgloop = imgloop
+ self.cowloop = cowloop
+
+ self.__created = False
+ self.__name = None
+ self.dmsetupcmd = find_binary_path("dmsetup")
+
+ """Load dm_snapshot if it isn't loaded"""
+ load_module("dm_snapshot")
+
+ def get_path(self):
+ if self.__name is None:
+ return None
+ return os.path.join("/dev/mapper", self.__name)
+ path = property(get_path)
+
+ def create(self):
+ if self.__created:
+ return
+
+ self.imgloop.create()
+ self.cowloop.create()
+
+ self.__name = "imgcreate-%d-%d" % (os.getpid(),
+ random.randint(0, 2**16))
+
+ size = os.stat(self.imgloop.lofile)[stat.ST_SIZE]
+
+ table = "0 %d snapshot %s %s p 8" % (size / 512,
+ self.imgloop.device,
+ self.cowloop.device)
+
+ args = [self.dmsetupcmd, "create", self.__name, "--table", table]
+ if runner.show(args) != 0:
+ self.cowloop.cleanup()
+ self.imgloop.cleanup()
+ raise SnapshotError("Could not create snapshot device using: " + ' '.join(args))
+
+ self.__created = True
+
+ def remove(self, ignore_errors = False):
+ if not self.__created:
+ return
+
+ time.sleep(2)
+ rc = runner.show([self.dmsetupcmd, "remove", self.__name])
+ if not ignore_errors and rc != 0:
+ raise SnapshotError("Could not remove snapshot device")
+
+ self.__name = None
+ self.__created = False
+
+ self.cowloop.cleanup()
+ self.imgloop.cleanup()
+
+ def get_cow_used(self):
+ if not self.__created:
+ return 0
+
+ #
+ # dmsetup status on a snapshot returns e.g.
+ # "0 8388608 snapshot 416/1048576"
+ # or, more generally:
+ # "A B snapshot C/D"
+ # where C is the number of 512 byte sectors in use
+ #
+ out = runner.outs([self.dmsetupcmd, "status", self.__name])
+ try:
+ return int((out.split()[3]).split('/')[0]) * 512
+ except ValueError:
+ raise SnapshotError("Failed to parse dmsetup status: " + out)
+
+def create_image_minimizer(path, image, minimal_size):
+ """
+ Builds a copy-on-write image which can be used to
+ create a device-mapper snapshot of an image where
+ the image's filesystem is as small as possible
+
+ The steps taken are:
+ 1) Create a sparse COW
+ 2) Loopback mount the image and the COW
+ 3) Create a device-mapper snapshot of the image
+ using the COW
+ 4) Resize the filesystem to the minimal size
+ 5) Determine the amount of space used in the COW
+ 6) Restroy the device-mapper snapshot
+ 7) Truncate the COW, removing unused space
+ 8) Create a squashfs of the COW
+ """
+ imgloop = LoopbackDisk(image, None) # Passing bogus size - doesn't matter
+
+ cowloop = SparseLoopbackDisk(os.path.join(os.path.dirname(path), "osmin"),
+ 64 * 1024 * 1024)
+
+ snapshot = DeviceMapperSnapshot(imgloop, cowloop)
+
+ try:
+ snapshot.create()
+
+ resize2fs(snapshot.path, minimal_size)
+
+ cow_used = snapshot.get_cow_used()
+ finally:
+ snapshot.remove(ignore_errors = (not sys.exc_info()[0] is None))
+
+ cowloop.truncate(cow_used)
+
+ mksquashfs(cowloop.lofile, path)
+
+ os.unlink(cowloop.lofile)
+
+def load_module(module):
+ found = False
+ for line in open('/proc/modules').xreadlines():
+ if line.startswith("%s " % module):
+ found = True
+ break
+ if not found:
+ msger.info("Loading %s..." % module)
+ runner.quiet(['modprobe', module])
+
+class LoopDevice(object):
+ def __init__(self, loopid=None):
+ self.device = None
+ self.loopid = loopid
+ self.created = False
+ self.kpartxcmd = find_binary_path("kpartx")
+ self.losetupcmd = find_binary_path("losetup")
+
+ def register(self, device):
+ self.device = device
+ self.loopid = None
+ #self.created = True
+
+ def reg_atexit(self):
+ import atexit
+ atexit.register(self.close)
+
+ def _genloopid(self):
+ import glob
+ if not glob.glob("/dev/loop[0-9]*"):
+ return 10
+
+ fint = lambda x: x[9:].isdigit() and int(x[9:]) or 0
+ maxid = 1 + max(filter(lambda x: x<256,
+ map(fint, glob.glob("/dev/loop[0-9]*"))))
+ if maxid < 10: maxid = 10
+ if maxid >= 256:
+ raise Exception("maxid >= 256")
+ return maxid
+
+ def _kpseek(self, device):
+ rc, out = runner.runtool([self.kpartxcmd, '-l', '-v', device])
+ if rc != 0:
+ raise MountError("Can't query dm snapshot on %s" % device)
+ for line in out.splitlines():
+ if line and line.startswith("loop"):
+ return True
+ return False
+
+ def _loseek(self, device):
+ import re
+ rc, out = runner.runtool([self.losetupcmd, '-a'])
+ if rc != 0:
+ raise MountError("Failed to run 'losetup -a'")
+ for line in out.splitlines():
+ m = re.match("([^:]+): .*", line)
+ if m and m.group(1) == device:
+ return True
+ return False
+
+ def create(self):
+ if not self.created:
+ if not self.loopid:
+ self.loopid = self._genloopid()
+ self.device = "/dev/loop%d" % self.loopid
+ if os.path.exists(self.device):
+ if self._loseek(self.device):
+ raise MountError("Device busy: %s" % self.device)
+ else:
+ self.created = True
+ return
+
+ mknod = find_binary_path('mknod')
+ rc = runner.show([mknod, '-m664', self.device, 'b', '7', str(self.loopid)])
+ if rc != 0:
+ raise MountError("Failed to create device %s" % self.device)
+ else:
+ self.created = True
+
+ def close(self):
+ if self.created:
+ try:
+ self.cleanup()
+ self.device = None
+ except MountError as e:
+ raise CreatorError("%s" % e)
+
+ def cleanup(self):
+
+ if self.device is None:
+ return
+
+
+ if self._kpseek(self.device):
+ runner.quiet([self.kpartxcmd, "-d", self.device])
+ if self._loseek(self.device):
+ runner.quiet([self.losetupcmd, "-d", self.device])
+ # FIXME: should sleep a while between two loseek
+ if self._loseek(self.device):
+ msger.warning("Can't cleanup loop device %s" % self.device)
+ elif self.loopid:
+ os.unlink(self.device)
+
+DEVICE_PIDFILE_DIR = "/var/tmp/mic/device"
+DEVICE_LOCKFILE = "/var/lock/__mic_loopdev.lock"
+
+def get_loop_device(losetupcmd, lofile):
+ import fcntl
+ makedirs(os.path.dirname(DEVICE_LOCKFILE))
+ fp = open(DEVICE_LOCKFILE, 'w')
+ fcntl.flock(fp, fcntl.LOCK_EX)
+ try:
+ loopdev = None
+ devinst = LoopDevice()
+
+ # clean up left loop device first
+ clean_loop_devices()
+
+ # provide an avaible loop device
+ rc, out = runner.runtool([losetupcmd, "-f"])
+ if rc == 0 and out:
+ loopdev = out.split()[0]
+ devinst.register(loopdev)
+ if not loopdev or not os.path.exists(loopdev):
+ devinst.create()
+ loopdev = devinst.device
+
+ # setup a loop device for image file
+ rc = runner.show([losetupcmd, loopdev, lofile])
+ if rc != 0:
+ raise MountError("Failed to setup loop device for '%s'" % lofile)
+
+ devinst.reg_atexit()
+
+ # try to save device and pid
+ makedirs(DEVICE_PIDFILE_DIR)
+ pidfile = os.path.join(DEVICE_PIDFILE_DIR, os.path.basename(loopdev))
+ if os.path.exists(pidfile):
+ os.unlink(pidfile)
+ with open(pidfile, 'w') as wf:
+ wf.write(str(os.getpid()))
+
+ except MountError as err:
+ raise CreatorError("%s" % str(err))
+ except:
+ raise
+ finally:
+ try:
+ fcntl.flock(fp, fcntl.LOCK_UN)
+ fp.close()
+ except:
+ pass
+
+ return loopdev
+
+def clean_loop_devices(piddir=DEVICE_PIDFILE_DIR):
+ if not os.path.exists(piddir) or not os.path.isdir(piddir):
+ return
+
+ for loopdev in os.listdir(piddir):
+ pidfile = os.path.join(piddir, loopdev)
+ try:
+ with open(pidfile, 'r') as rf:
+ devpid = int(rf.read())
+ except:
+ devpid = None
+
+ # if the process using this device is alive, skip it
+ if not devpid or os.path.exists(os.path.join('/proc', str(devpid))):
+ continue
+
+ # try to clean it up
+ try:
+ devinst = LoopDevice()
+ devinst.register(os.path.join('/dev', loopdev))
+ devinst.cleanup()
+ os.unlink(pidfile)
+ except:
+ pass
+
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2013 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+""" This module implements a simple GPT partitions parser which can read the
+GPT header and the GPT partition table. """
+
+import struct
+import uuid
+import binascii
+from mic.utils.errors import MountError
+
+_GPT_HEADER_FORMAT = "<8s4sIIIQQQQ16sQIII"
+_GPT_HEADER_SIZE = struct.calcsize(_GPT_HEADER_FORMAT)
+_GPT_ENTRY_FORMAT = "<16s16sQQQ72s"
+_GPT_ENTRY_SIZE = struct.calcsize(_GPT_ENTRY_FORMAT)
+_SUPPORTED_GPT_REVISION = '\x00\x00\x01\x00'
+
+def _stringify_uuid(binary_uuid):
+ """ A small helper function to transform a binary UUID into a string
+ format. """
+
+ uuid_str = str(uuid.UUID(bytes_le = binary_uuid))
+
+ return uuid_str.upper()
+
+def _calc_header_crc(raw_hdr):
+ """ Calculate GPT header CRC32 checksum. The 'raw_hdr' parameter has to
+ be a list or a tuple containing all the elements of the GPT header in a
+ "raw" form, meaning that it should simply contain "unpacked" disk data.
+ """
+
+ raw_hdr = list(raw_hdr)
+ raw_hdr[3] = 0
+ raw_hdr = struct.pack(_GPT_HEADER_FORMAT, *raw_hdr)
+
+ return binascii.crc32(raw_hdr) & 0xFFFFFFFF
+
+def _validate_header(raw_hdr):
+ """ Validate the GPT header. The 'raw_hdr' parameter has to be a list or a
+ tuple containing all the elements of the GPT header in a "raw" form,
+ meaning that it should simply contain "unpacked" disk data. """
+
+ # Validate the signature
+ if raw_hdr[0] != 'EFI PART':
+ raise MountError("GPT partition table not found")
+
+ # Validate the revision
+ if raw_hdr[1] != _SUPPORTED_GPT_REVISION:
+ raise MountError("Unsupported GPT revision '%s', supported revision " \
+ "is '%s'" % \
+ (binascii.hexlify(raw_hdr[1]),
+ binascii.hexlify(_SUPPORTED_GPT_REVISION)))
+
+ # Validate header size
+ if raw_hdr[2] != _GPT_HEADER_SIZE:
+ raise MountError("Bad GPT header size: %d bytes, expected %d" % \
+ (raw_hdr[2], _GPT_HEADER_SIZE))
+
+ crc = _calc_header_crc(raw_hdr)
+ if raw_hdr[3] != crc:
+ raise MountError("GPT header crc mismatch: %#x, should be %#x" % \
+ (crc, raw_hdr[3]))
+
+class GptParser:
+ """ GPT partition table parser. Allows reading the GPT header and the
+ partition table, as well as modifying the partition table records. """
+
+ def __init__(self, disk_path, sector_size = 512):
+ """ The class constructor which accepts the following parameters:
+ * disk_path - full path to the disk image or device node
+ * sector_size - size of a disk sector in bytes """
+
+ self.sector_size = sector_size
+ self.disk_path = disk_path
+
+ try:
+ self._disk_obj = open(disk_path, 'r+b')
+ except IOError as err:
+ raise MountError("Cannot open file '%s' for reading GPT " \
+ "partitions: %s" % (disk_path, err))
+
+ def __del__(self):
+ """ The class destructor. """
+
+ self._disk_obj.close()
+
+ def _read_disk(self, offset, size):
+ """ A helper function which reads 'size' bytes from offset 'offset' of
+ the disk and checks all the error conditions. """
+
+ self._disk_obj.seek(offset)
+ try:
+ data = self._disk_obj.read(size)
+ except IOError as err:
+ raise MountError("cannot read from '%s': %s" % \
+ (self.disk_path, err))
+
+ if len(data) != size:
+ raise MountError("cannot read %d bytes from offset '%d' of '%s', " \
+ "read only %d bytes" % \
+ (size, offset, self.disk_path, len(data)))
+
+ return data
+
+ def _write_disk(self, offset, buf):
+ """ A helper function which writes buffer 'buf' to offset 'offset' of
+ the disk. This function takes care of unaligned writes and checks all
+ the error conditions. """
+
+ # Since we may be dealing with a block device, we only can write in
+ # 'self.sector_size' chunks. Find the aligned starting and ending
+ # disk offsets to read.
+ start = (offset / self.sector_size) * self.sector_size
+ end = ((start + len(buf)) / self.sector_size + 1) * self.sector_size
+
+ data = self._read_disk(start, end - start)
+ off = offset - start
+ data = data[:off] + buf + data[off + len(buf):]
+
+ self._disk_obj.seek(start)
+ try:
+ self._disk_obj.write(data)
+ except IOError as err:
+ raise MountError("cannot write to '%s': %s" % (self.disk_path, err))
+
+ def read_header(self, primary = True):
+ """ Read and verify the GPT header and return a dictionary containing
+ the following elements:
+
+ 'signature' : header signature
+ 'revision' : header revision
+ 'hdr_size' : header size in bytes
+ 'hdr_crc' : header CRC32
+ 'hdr_lba' : LBA of this header
+ 'hdr_offs' : byte disk offset of this header
+ 'backup_lba' : backup header LBA
+ 'backup_offs' : byte disk offset of backup header
+ 'first_lba' : first usable LBA for partitions
+ 'first_offs' : first usable byte disk offset for partitions
+ 'last_lba' : last usable LBA for partitions
+ 'last_offs' : last usable byte disk offset for partitions
+ 'disk_uuid' : UUID of the disk
+ 'ptable_lba' : starting LBA of array of partition entries
+ 'ptable_offs' : disk byte offset of the start of the partition table
+ 'ptable_size' : partition table size in bytes
+ 'entries_cnt' : number of available partition table entries
+ 'entry_size' : size of a single partition entry
+ 'ptable_crc' : CRC32 of the partition table
+ 'primary' : a boolean, if 'True', this is the primary GPT header,
+ if 'False' - the secondary
+ 'primary_str' : contains string "primary" if this is the primary GPT
+ header, and "backup" otherwise
+
+ This dictionary corresponds to the GPT header format. Please, see the
+ UEFI standard for the description of these fields.
+
+ If the 'primary' parameter is 'True', the primary GPT header is read,
+ otherwise the backup GPT header is read instead. """
+
+ # Read and validate the primary GPT header
+ raw_hdr = self._read_disk(self.sector_size, _GPT_HEADER_SIZE)
+ raw_hdr = struct.unpack(_GPT_HEADER_FORMAT, raw_hdr)
+ _validate_header(raw_hdr)
+ primary_str = "primary"
+
+ if not primary:
+ # Read and validate the backup GPT header
+ raw_hdr = self._read_disk(raw_hdr[6] * self.sector_size, _GPT_HEADER_SIZE)
+ raw_hdr = struct.unpack(_GPT_HEADER_FORMAT, raw_hdr)
+ _validate_header(raw_hdr)
+ primary_str = "backup"
+
+ return { 'signature' : raw_hdr[0],
+ 'revision' : raw_hdr[1],
+ 'hdr_size' : raw_hdr[2],
+ 'hdr_crc' : raw_hdr[3],
+ 'hdr_lba' : raw_hdr[5],
+ 'hdr_offs' : raw_hdr[5] * self.sector_size,
+ 'backup_lba' : raw_hdr[6],
+ 'backup_offs' : raw_hdr[6] * self.sector_size,
+ 'first_lba' : raw_hdr[7],
+ 'first_offs' : raw_hdr[7] * self.sector_size,
+ 'last_lba' : raw_hdr[8],
+ 'last_offs' : raw_hdr[8] * self.sector_size,
+ 'disk_uuid' :_stringify_uuid(raw_hdr[9]),
+ 'ptable_lba' : raw_hdr[10],
+ 'ptable_offs' : raw_hdr[10] * self.sector_size,
+ 'ptable_size' : raw_hdr[11] * raw_hdr[12],
+ 'entries_cnt' : raw_hdr[11],
+ 'entry_size' : raw_hdr[12],
+ 'ptable_crc' : raw_hdr[13],
+ 'primary' : primary,
+ 'primary_str' : primary_str }
+
+ def _read_raw_ptable(self, header):
+ """ Read and validate primary or backup partition table. The 'header'
+ argument is the GPT header. If it is the primary GPT header, then the
+ primary partition table is read and validated, otherwise - the backup
+ one. The 'header' argument is a dictionary which is returned by the
+ 'read_header()' method. """
+
+ raw_ptable = self._read_disk(header['ptable_offs'],
+ header['ptable_size'])
+
+ crc = binascii.crc32(raw_ptable) & 0xFFFFFFFF
+ if crc != header['ptable_crc']:
+ raise MountError("Partition table at LBA %d (%s) is corrupted" % \
+ (header['ptable_lba'], header['primary_str']))
+
+ return raw_ptable
+
+ def get_partitions(self, primary = True):
+ """ This is a generator which parses the GPT partition table and
+ generates the following dictionary for each partition:
+
+ 'index' : the index of the partition table endry
+ 'offs' : byte disk offset of the partition table entry
+ 'type_uuid' : partition type UUID
+ 'part_uuid' : partition UUID
+ 'first_lba' : the first LBA
+ 'last_lba' : the last LBA
+ 'flags' : attribute flags
+ 'name' : partition name
+ 'primary' : a boolean, if 'True', this is the primary partition
+ table, if 'False' - the secondary
+ 'primary_str' : contains string "primary" if this is the primary GPT
+ header, and "backup" otherwise
+
+ This dictionary corresponds to the GPT header format. Please, see the
+ UEFI standard for the description of these fields.
+
+ If the 'primary' parameter is 'True', partitions from the primary GPT
+ partition table are generated, otherwise partitions from the backup GPT
+ partition table are generated. """
+
+ if primary:
+ primary_str = "primary"
+ else:
+ primary_str = "backup"
+
+ header = self.read_header(primary)
+ raw_ptable = self._read_raw_ptable(header)
+
+ for index in xrange(0, header['entries_cnt']):
+ start = header['entry_size'] * index
+ end = start + header['entry_size']
+ raw_entry = struct.unpack(_GPT_ENTRY_FORMAT, raw_ptable[start:end])
+
+ if raw_entry[2] == 0 or raw_entry[3] == 0:
+ continue
+
+ part_name = str(raw_entry[5].decode('UTF-16').split('\0', 1)[0])
+
+ yield { 'index' : index,
+ 'offs' : header['ptable_offs'] + start,
+ 'type_uuid' : _stringify_uuid(raw_entry[0]),
+ 'part_uuid' : _stringify_uuid(raw_entry[1]),
+ 'first_lba' : raw_entry[2],
+ 'last_lba' : raw_entry[3],
+ 'flags' : raw_entry[4],
+ 'name' : part_name,
+ 'primary' : primary,
+ 'primary_str' : primary_str }
+
+ def _change_partition(self, header, entry):
+ """ A helper function for 'change_partitions()' which changes a
+ a paricular instance of the partition table (primary or backup). """
+
+ if entry['index'] >= header['entries_cnt']:
+ raise MountError("Partition table at LBA %d has only %d " \
+ "records cannot change record number " % \
+ (header['entries_cnt'], entry['index']))
+ # Read raw GPT header
+ raw_hdr = self._read_disk(header['hdr_offs'], _GPT_HEADER_SIZE)
+ raw_hdr = list(struct.unpack(_GPT_HEADER_FORMAT, raw_hdr))
+ _validate_header(raw_hdr)
+
+ # Prepare the new partition table entry
+ raw_entry = struct.pack(_GPT_ENTRY_FORMAT,
+ uuid.UUID(entry['type_uuid']).bytes_le,
+ uuid.UUID(entry['part_uuid']).bytes_le,
+ entry['first_lba'],
+ entry['last_lba'],
+ entry['flags'],
+ entry['name'].encode('UTF-16LE'))
+
+ # Write the updated entry to the disk
+ entry_offs = header['ptable_offs'] + \
+ header['entry_size'] * entry['index']
+ self._write_disk(entry_offs, raw_entry)
+
+ # Calculate and update partition table CRC32
+ raw_ptable = self._read_disk(header['ptable_offs'],
+ header['ptable_size'])
+ raw_hdr[13] = binascii.crc32(raw_ptable) & 0xFFFFFFFF
+
+ # Calculate and update the GPT header CRC
+ raw_hdr[3] = _calc_header_crc(raw_hdr)
+
+ # Write the updated header to the disk
+ raw_hdr = struct.pack(_GPT_HEADER_FORMAT, *raw_hdr)
+ self._write_disk(header['hdr_offs'], raw_hdr)
+
+ def change_partition(self, entry):
+ """ Change a GPT partition. The 'entry' argument has the same format as
+ 'get_partitions()' returns. This function simply changes the partition
+ table record corresponding to 'entry' in both, the primary and the
+ backup GPT partition tables. The parition table CRC is re-calculated
+ and the GPT headers are modified accordingly. """
+
+ # Change the primary partition table
+ header = self.read_header(True)
+ self._change_partition(header, entry)
+
+ # Change the backup partition table
+ header = self.read_header(False)
+ self._change_partition(header, entry)
--- /dev/null
+#!/usr/bin/python
+
+# Copyright (c) 2014 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+import sys
+import fcntl
+import struct
+import termios
+
+from mic import msger
+from mic.utils import runner
+from mic.utils.errors import CreatorError
+from mic.utils.safeurl import SafeURL
+
+from urlgrabber import grabber
+from urlgrabber import __version__ as grabber_version
+
+def myurlgrab(url, filename, proxies, progress_obj = None):
+ g = grabber.URLGrabber()
+ if progress_obj is None:
+ progress_obj = TextProgress()
+
+ if url.startswith("file:/"):
+ filepath = "/%s" % url.replace("file:", "").lstrip('/')
+ if not os.path.exists(filepath):
+ raise CreatorError("URLGrabber error: can't find file %s" % url)
+ if url.endswith('.rpm'):
+ return filepath
+ else:
+ # untouch repometadata in source path
+ runner.show(['cp', '-f', filepath, filename])
+
+ else:
+ try:
+ # cast url to str here, sometimes it can be unicode,
+ # but pycurl only accept str
+ filename = g.urlgrab(url=str(url),
+ filename=filename,
+ ssl_verify_host=False,
+ ssl_verify_peer=False,
+ proxies=proxies,
+ http_headers=(('Pragma', 'no-cache'),),
+ quote=0,
+ progress_obj=progress_obj)
+ except grabber.URLGrabError as err:
+ tmp = SafeURL(url)
+ msg = str(err)
+
+ if msg.find(url) < 0:
+ msg += ' on %s' % tmp
+ else:
+ msg = msg.replace(url, tmp)
+
+ raise CreatorError(msg)
+
+ return filename
+
+def terminal_width(fd=1):
+ """ Get the real terminal width """
+ try:
+ buf = 'abcdefgh'
+ buf = fcntl.ioctl(fd, termios.TIOCGWINSZ, buf)
+ return struct.unpack('hhhh', buf)[1]
+ except: # IOError
+ return 80
+
+def truncate_url(url, width):
+ return os.path.basename(url)[0:width]
+
+class TextProgress(object):
+ # make the class as singleton
+ _instance = None
+ def __new__(cls, *args, **kwargs):
+ if not cls._instance:
+ cls._instance = super(TextProgress, cls).__new__(cls, *args, **kwargs)
+
+ return cls._instance
+
+ def __init__(self, totalnum = None):
+ self.total = totalnum
+ self.counter = 1
+
+ def start(self, filename, url, *args, **kwargs):
+ self.url = url
+ self.termwidth = terminal_width()
+ if self.total is None:
+ msger.info("Retrieving %s ..." % truncate_url(self.url, self.termwidth - 15))
+ else:
+ msger.info("Retrieving %s [%d/%d] ..." % (truncate_url(self.url, self.termwidth - 25), self.counter, self.total))
+
+ def update(self, *args):
+ pass
+
+ def end(self, *args):
+ if self.counter == self.total:
+ msger.raw("\n")
+
+ if self.total is not None:
+ self.counter += 1
+
--- /dev/null
+# Copyright (c) 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2 of the License, or any later version.
+
+import os
+import errno
+
+class LockfileError(Exception):
+ """ Lockfile Exception"""
+ pass
+
+class SimpleLockfile(object):
+ """ Simple implementation of lockfile """
+ def __init__(self, fpath):
+ self.fpath = fpath
+ self.lockf = None
+
+ def acquire(self):
+ """ acquire the lock """
+ try:
+ self.lockf = os.open(self.fpath,
+ os.O_CREAT | os.O_EXCL | os.O_WRONLY)
+ except OSError as err:
+ if err.errno == errno.EEXIST:
+ raise LockfileError("File %s is locked already" % self.fpath)
+ raise
+ finally:
+ if self.lockf:
+ os.close(self.lockf)
+
+ def release(self):
+ """ release the lock """
+ try:
+ os.remove(self.fpath)
+ except OSError as err:
+ if err.errno == errno.ENOENT:
+ pass
+
+ def __enter__(self):
+ self.acquire()
+ return self
+
+ def __exit__(self, *args):
+ self.release()
+
+ def __del__(self):
+ self.release()
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2010, 2011 Intel Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+from __future__ import with_statement
+import os
+import sys
+import time
+import tempfile
+import re
+import shutil
+import glob
+import hashlib
+import subprocess
+import platform
+import traceback
+
+
+try:
+ import sqlite3 as sqlite
+except ImportError:
+ import sqlite
+
+try:
+ from xml.etree import cElementTree
+except ImportError:
+ import cElementTree
+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
+from mic.utils.proxy import get_proxy_for
+from mic.utils import runner
+from mic.utils import rpmmisc
+from mic.utils.safeurl import SafeURL
+
+
+RPM_RE = re.compile("(.*)\.(.*) (.*)-(.*)")
+RPM_FMT = "%(name)s.%(arch)s %(version)s-%(release)s"
+SRPM_RE = re.compile("(.*)-(\d+.*)-(\d+\.\d+).src.rpm")
+
+
+def build_name(kscfg, release=None, prefix = None, suffix = None):
+ """Construct and return an image name string.
+
+ This is a utility function to help create sensible name and fslabel
+ strings. The name is constructed using the sans-prefix-and-extension
+ kickstart filename and the supplied prefix and suffix.
+
+ kscfg -- a path to a kickstart file
+ release -- a replacement to suffix for image release
+ prefix -- a prefix to prepend to the name; defaults to None, which causes
+ no prefix to be used
+ suffix -- a suffix to append to the name; defaults to None, which causes
+ a YYYYMMDDHHMM suffix to be used
+
+ Note, if maxlen is less then the len(suffix), you get to keep both pieces.
+
+ """
+ name = os.path.basename(kscfg)
+ idx = name.rfind('.')
+ if idx >= 0:
+ name = name[:idx]
+
+ if release is not None:
+ suffix = ""
+ if prefix is None:
+ prefix = ""
+ if suffix is None:
+ suffix = time.strftime("%Y%m%d%H%M")
+
+ if name.startswith(prefix):
+ name = name[len(prefix):]
+
+ prefix = "%s-" % prefix if prefix else ""
+ suffix = "-%s" % suffix if suffix else ""
+
+ ret = prefix + name + suffix
+ return ret
+
+def get_distro():
+ """Detect linux distribution, support "meego"
+ """
+
+ support_dists = ('SuSE',
+ 'debian',
+ 'fedora',
+ 'redhat',
+ 'centos',
+ 'meego',
+ 'moblin',
+ 'tizen')
+ try:
+ (dist, ver, id) = platform.linux_distribution( \
+ supported_dists = support_dists)
+ except:
+ (dist, ver, id) = platform.dist( \
+ supported_dists = support_dists)
+
+ return (dist, ver, id)
+
+def get_hostname():
+ """Get hostname
+ """
+ return platform.node()
+
+def get_hostname_distro_str():
+ """Get composited string for current linux distribution
+ """
+ (dist, ver, id) = get_distro()
+ hostname = get_hostname()
+
+ if not dist:
+ return "%s(Unknown Linux Distribution)" % hostname
+ else:
+ distro_str = ' '.join(map(str.strip, (hostname, dist, ver, id)))
+ return distro_str.strip()
+
+_LOOP_RULE_PTH = None
+
+def hide_loopdev_presentation():
+ udev_rules = "80-prevent-loop-present.rules"
+ udev_rules_dir = [
+ '/usr/lib/udev/rules.d/',
+ '/lib/udev/rules.d/',
+ '/etc/udev/rules.d/'
+ ]
+
+ global _LOOP_RULE_PTH
+
+ for rdir in udev_rules_dir:
+ if os.path.exists(rdir):
+ _LOOP_RULE_PTH = os.path.join(rdir, udev_rules)
+
+ if not _LOOP_RULE_PTH:
+ return
+
+ try:
+ with open(_LOOP_RULE_PTH, 'w') as wf:
+ wf.write('KERNEL=="loop*", ENV{UDISKS_PRESENTATION_HIDE}="1"')
+
+ runner.quiet('udevadm trigger')
+ except:
+ pass
+
+def unhide_loopdev_presentation():
+ #global _LOOP_RULE_PTH
+
+ if not _LOOP_RULE_PTH:
+ return
+
+ try:
+ os.unlink(_LOOP_RULE_PTH)
+ runner.quiet('udevadm trigger')
+ except:
+ pass
+
+def extract_rpm(rpmfile, targetdir):
+ rpm2cpio = find_binary_path("rpm2cpio")
+ cpio = find_binary_path("cpio")
+
+ olddir = os.getcwd()
+ os.chdir(targetdir)
+
+ msger.verbose("Extract rpm file with cpio: %s" % rpmfile)
+ p1 = subprocess.Popen([rpm2cpio, rpmfile], stdout=subprocess.PIPE)
+ p2 = subprocess.Popen([cpio, "-idv"], stdin=p1.stdout,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ p1.stdout.close()
+ (sout, serr) = p2.communicate()
+ msger.verbose(sout or serr)
+
+ os.chdir(olddir)
+
+def human_size(size):
+ """Return human readable string for Bytes size
+ """
+
+ if size <= 0:
+ return "0M"
+ import math
+ measure = ['B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
+ expo = int(math.log(size, 1024))
+ mant = float(size/math.pow(1024, expo))
+ return "{0:.1f}{1:s}".format(mant, measure[expo])
+
+def get_block_size(file_obj):
+ """ Returns block size for file object 'file_obj'. Errors are indicated by
+ the 'IOError' exception. """
+
+ from fcntl import ioctl
+ import struct
+
+ # Get the block size of the host file-system for the image file by calling
+ # the FIGETBSZ ioctl (number 2).
+ binary_data = ioctl(file_obj, 2, struct.pack('I', 0))
+ return struct.unpack('I', binary_data)[0]
+
+def check_space_pre_cp(src, dst):
+ """Check whether disk space is enough before 'cp' like
+ operations, else exception will be raised.
+ """
+
+ srcsize = get_file_size(src) * 1024 * 1024
+ freesize = get_filesystem_avail(dst)
+ if srcsize > freesize:
+ raise CreatorError("space on %s(%s) is not enough for about %s files"
+ % (dst, human_size(freesize), human_size(srcsize)))
+
+def calc_hashes(file_path, hash_names, start = 0, end = None):
+ """ Calculate hashes for a file. The 'file_path' argument is the file
+ to calculate hash functions for, 'start' and 'end' are the starting and
+ ending file offset to calculate the has functions for. The 'hash_names'
+ argument is a list of hash names to calculate. Returns the the list
+ of calculated hash values in the hexadecimal form in the same order
+ as 'hash_names'.
+ """
+ if end == None:
+ end = os.path.getsize(file_path)
+
+ chunk_size = 65536
+ to_read = end - start
+ read = 0
+
+ hashes = []
+ for hash_name in hash_names:
+ hashes.append(hashlib.new(hash_name))
+
+ with open(file_path, "rb") as f:
+ f.seek(start)
+
+ while read < to_read:
+ if read + chunk_size > to_read:
+ chunk_size = to_read - read
+ chunk = f.read(chunk_size)
+ for hash_obj in hashes:
+ hash_obj.update(chunk)
+ read += chunk_size
+
+ result = []
+ for hash_obj in hashes:
+ result.append(hash_obj.hexdigest())
+
+ return result
+
+def get_md5sum(fpath):
+ return calc_hashes(fpath, ('md5', ))[0]
+
+def get_sha1sum(fpath):
+ return calc_hashes(fpath, ('sha1', ))[0]
+
+def get_sha256sum(fpath):
+ return calc_hashes(fpath, ('sha256', ))[0]
+
+def normalize_ksfile(ksconf, release, arch):
+ '''
+ Return the name of a normalized ks file in which macro variables
+ @BUILD_ID@ and @ARCH@ are replace with real values.
+
+ The original ks file is returned if no special macro is used, otherwise
+ a temp file is created and returned, which will be deleted when program
+ exits normally.
+ '''
+
+ if not release:
+ release = "latest"
+ if not arch or re.match(r'i.86', arch):
+ arch = "ia32"
+
+ with open(ksconf) as f:
+ ksc = f.read()
+
+ if "@ARCH@" not in ksc and "@BUILD_ID@" not in ksc:
+ return ksconf
+
+ msger.info("Substitute macro variable @BUILD_ID@/@ARCH@ in ks: %s" % ksconf)
+ ksc = ksc.replace("@ARCH@", arch)
+ ksc = ksc.replace("@BUILD_ID@", release)
+
+ fd, ksconf = tempfile.mkstemp(prefix=os.path.basename(ksconf))
+ os.write(fd, ksc)
+ os.close(fd)
+
+ msger.debug('normalized ks file:%s' % ksconf)
+
+ def remove_temp_ks():
+ try:
+ os.unlink(ksconf)
+ except OSError as err:
+ msger.warning('Failed to remove temp ks file:%s:%s' % (ksconf, err))
+
+ import atexit
+ atexit.register(remove_temp_ks)
+
+ return ksconf
+
+
+def _check_mic_chroot(rootdir):
+ def _path(path):
+ return rootdir.rstrip('/') + path
+
+ release_files = map(_path, [ "/etc/moblin-release",
+ "/etc/meego-release",
+ "/etc/tizen-release"])
+
+ if not any(map(os.path.exists, release_files)):
+ msger.warning("Dir %s is not a MeeGo/Tizen chroot env" % rootdir)
+
+ if not glob.glob(rootdir + "/boot/vmlinuz-*"):
+ msger.warning("Failed to find kernel module under %s" % rootdir)
+
+ return
+
+def selinux_check(arch, fstypes):
+ try:
+ getenforce = find_binary_path('getenforce')
+ except CreatorError:
+ return
+
+ selinux_status = runner.outs([getenforce])
+ if arch and arch.startswith("arm") and selinux_status == "Enforcing":
+ raise CreatorError("Can't create arm image if selinux is enabled, "
+ "please run 'setenforce 0' to disable selinux")
+
+ use_btrfs = filter(lambda typ: typ == 'btrfs', fstypes)
+ if use_btrfs and selinux_status == "Enforcing":
+ raise CreatorError("Can't create btrfs image if selinux is enabled,"
+ " please run 'setenforce 0' to disable selinux")
+
+def get_image_type(path):
+ def _get_extension_name(path):
+ match = re.search("(?<=\.)\w+$", path)
+ if match:
+ return match.group(0)
+ else:
+ return None
+
+ if os.path.isdir(path):
+ _check_mic_chroot(path)
+ return "fs"
+
+ maptab = {
+ "tar": "loop",
+ "raw":"raw",
+ "vmdk":"vmdk",
+ "vdi":"vdi",
+ "iso":"livecd",
+ "usbimg":"liveusb",
+ }
+
+ extension = _get_extension_name(path)
+ if extension in maptab:
+ return maptab[extension]
+
+ fd = open(path, "rb")
+ file_header = fd.read(1024)
+ fd.close()
+ vdi_flag = "<<< Sun VirtualBox Disk Image >>>"
+ if file_header[0:len(vdi_flag)] == vdi_flag:
+ return maptab["vdi"]
+
+ #Checking f2fs fs type.
+ blkidcmd = find_binary_path("blkid")
+ out = runner.outs([blkidcmd, '-o', 'value', '-s', 'TYPE', path])
+ if out == "f2fs":
+ return "f2fsimg"
+ output = runner.outs(['file', path])
+ isoptn = re.compile(r".*ISO 9660 CD-ROM filesystem.*(bootable).*")
+ usbimgptn = re.compile(r".*x86 boot sector.*active.*")
+ rawptn = re.compile(r".*x86 boot sector.*")
+ vmdkptn = re.compile(r".*VMware. disk image.*")
+ ext3fsimgptn = re.compile(r".*Linux.*ext3 filesystem data.*")
+ ext4fsimgptn = re.compile(r".*Linux.*ext4 filesystem data.*")
+ btrfsimgptn = re.compile(r".*BTRFS.*")
+ if isoptn.match(output):
+ return maptab["iso"]
+ elif usbimgptn.match(output):
+ return maptab["usbimg"]
+ elif rawptn.match(output):
+ return maptab["raw"]
+ elif vmdkptn.match(output):
+ return maptab["vmdk"]
+ elif ext3fsimgptn.match(output):
+ return "ext3fsimg"
+ elif ext4fsimgptn.match(output):
+ return "ext4fsimg"
+ elif btrfsimgptn.match(output):
+ return "btrfsimg"
+ else:
+ raise CreatorError("Cannot detect the type of image: %s" % path)
+
+
+def get_file_size(filename):
+ """ Return size in MB unit """
+ cmd = ['du', "-s", "-b", "-B", "1M", filename]
+ rc, duOutput = runner.runtool(cmd)
+ if rc != 0:
+ raise CreatorError("Failed to run: %s" % ' '.join(cmd))
+ size1 = int(duOutput.split()[0])
+
+ cmd = ['du', "-s", "-B", "1M", filename]
+ rc, duOutput = runner.runtool(cmd)
+ if rc != 0:
+ raise CreatorError("Failed to run: %s" % ' '.join(cmd))
+
+ size2 = int(duOutput.split()[0])
+ return max(size1, size2)
+
+
+def get_filesystem_avail(fs):
+ vfstat = os.statvfs(fs)
+ return vfstat.f_bavail * vfstat.f_bsize
+
+def convert_image(srcimg, srcfmt, dstimg, dstfmt):
+ #convert disk format
+ if dstfmt != "raw":
+ raise CreatorError("Invalid destination image format: %s" % dstfmt)
+ msger.debug("converting %s image to %s" % (srcimg, dstimg))
+ if srcfmt == "vmdk":
+ path = find_binary_path("qemu-img")
+ argv = [path, "convert", "-f", "vmdk", srcimg, "-O", dstfmt, dstimg]
+ elif srcfmt == "vdi":
+ path = find_binary_path("VBoxManage")
+ argv = [path, "internalcommands", "converttoraw", srcimg, dstimg]
+ else:
+ raise CreatorError("Invalid soure image format: %s" % srcfmt)
+
+ rc = runner.show(argv)
+ if rc == 0:
+ msger.debug("convert successful")
+ if rc != 0:
+ raise CreatorError("Unable to convert disk to %s" % dstfmt)
+
+def uncompress_squashfs(squashfsimg, outdir):
+ """Uncompress file system from squshfs image"""
+ unsquashfs = find_binary_path("unsquashfs")
+ args = [ unsquashfs, "-d", outdir, squashfsimg ]
+ rc = runner.show(args)
+ if (rc != 0):
+ raise SquashfsError("Failed to uncompress %s." % squashfsimg)
+
+def mkdtemp(dir = "/var/tmp", prefix = "mic-tmp-"):
+ """ FIXME: use the dir in mic.conf instead """
+
+ makedirs(dir)
+ return tempfile.mkdtemp(dir = dir, prefix = prefix)
+
+def get_repostrs_from_ks(ks):
+ def _get_temp_reponame(baseurl):
+ md5obj = hashlib.md5(baseurl)
+ tmpreponame = "%s" % md5obj.hexdigest()
+ return tmpreponame
+
+ kickstart_repos = []
+
+ for repodata in ks.handler.repo.repoList:
+ repo = {}
+ for attr in ('name',
+ 'baseurl',
+ 'mirrorlist',
+ 'includepkgs', # val is list
+ 'excludepkgs', # val is list
+ 'cost', # int
+ 'priority',# int
+ 'save',
+ 'proxy',
+ 'proxyuser',
+ 'proxypasswd',
+ 'proxypasswd',
+ 'debuginfo',
+ 'source',
+ 'gpgkey',
+ 'ssl_verify'):
+ if hasattr(repodata, attr) and getattr(repodata, attr):
+ repo[attr] = getattr(repodata, attr)
+
+ if 'name' not in repo:
+ repo['name'] = _get_temp_reponame(repodata.baseurl)
+ if hasattr(repodata, 'baseurl') and getattr(repodata, 'baseurl'):
+ repo['baseurl'] = SafeURL(getattr(repodata, 'baseurl'),
+ getattr(repodata, 'user', None),
+ getattr(repodata, 'passwd', None))
+
+ kickstart_repos.append(repo)
+
+ return kickstart_repos
+
+def _get_uncompressed_data_from_url(url, filename, proxies):
+ filename = myurlgrab(url.full, filename, proxies)
+ suffix = None
+ if filename.endswith(".gz"):
+ suffix = ".gz"
+ runner.quiet(['gunzip', "-f", filename])
+ elif filename.endswith(".bz2"):
+ suffix = ".bz2"
+ runner.quiet(['bunzip2', "-f", filename])
+ if suffix:
+ filename = filename.replace(suffix, "")
+ return filename
+
+def _get_metadata_from_repo(baseurl, proxies, cachedir, reponame, filename,
+ sumtype=None, checksum=None):
+ url = baseurl.join(filename)
+ filename_tmp = str("%s/%s/%s" % (cachedir, reponame, os.path.basename(filename)))
+ if os.path.splitext(filename_tmp)[1] in (".gz", ".bz2"):
+ filename = os.path.splitext(filename_tmp)[0]
+ else:
+ filename = filename_tmp
+ if sumtype and checksum and os.path.exists(filename):
+ try:
+ sumcmd = find_binary_path("%ssum" % sumtype)
+ except:
+ file_checksum = None
+ else:
+ file_checksum = runner.outs([sumcmd, filename]).split()[0]
+
+ if file_checksum and file_checksum == checksum:
+ return filename
+
+ return _get_uncompressed_data_from_url(url,filename_tmp,proxies)
+
+def get_metadata_from_repos(repos, cachedir):
+ my_repo_metadata = []
+ for repo in repos:
+ reponame = repo.name
+ baseurl = repo.baseurl
+
+ if hasattr(repo, 'proxy'):
+ proxy = repo.proxy
+ else:
+ proxy = get_proxy_for(baseurl)
+
+ proxies = None
+ if proxy:
+ proxies = {str(baseurl.split(":")[0]): str(proxy)}
+
+ makedirs(os.path.join(cachedir, reponame))
+ url = baseurl.join("repodata/repomd.xml")
+ filename = os.path.join(cachedir, reponame, 'repomd.xml')
+ repomd = myurlgrab(url.full, filename, proxies)
+ try:
+ root = xmlparse(repomd)
+ except SyntaxError:
+ raise CreatorError("repomd.xml syntax error.")
+
+ ns = root.getroot().tag
+ ns = ns[0:ns.rindex("}")+1]
+
+ filepaths = {}
+ checksums = {}
+ sumtypes = {}
+
+ for elm in root.getiterator("%sdata" % ns):
+ if elm.attrib["type"] == "patterns":
+ filepaths['patterns'] = elm.find("%slocation" % ns).attrib['href']
+ checksums['patterns'] = elm.find("%sopen-checksum" % ns).text
+ sumtypes['patterns'] = elm.find("%sopen-checksum" % ns).attrib['type']
+ break
+
+ for elm in root.getiterator("%sdata" % ns):
+ #"group" type has no "open-checksum" filed, remove it.
+ if elm.attrib["type"] == "group_gz":
+ filepaths['comps'] = elm.find("%slocation" % ns).attrib['href']
+ checksums['comps'] = elm.find("%sopen-checksum" % ns).text
+ sumtypes['comps'] = elm.find("%sopen-checksum" % ns).attrib['type']
+ break
+
+ primary_type = None
+ for elm in root.getiterator("%sdata" % ns):
+ if elm.attrib["type"] in ("primary_db", "primary"):
+ primary_type = elm.attrib["type"]
+ filepaths['primary'] = elm.find("%slocation" % ns).attrib['href']
+ checksums['primary'] = elm.find("%sopen-checksum" % ns).text
+ sumtypes['primary'] = elm.find("%sopen-checksum" % ns).attrib['type']
+ break
+
+ if not primary_type:
+ continue
+
+ for item in ("primary", "patterns", "comps"):
+ if item not in filepaths:
+ filepaths[item] = None
+ continue
+ if not filepaths[item]:
+ continue
+ filepaths[item] = _get_metadata_from_repo(baseurl,
+ proxies,
+ cachedir,
+ reponame,
+ filepaths[item],
+ sumtypes[item],
+ checksums[item])
+
+ """ Get repo key """
+ try:
+ repokey = _get_metadata_from_repo(baseurl,
+ proxies,
+ cachedir,
+ reponame,
+ "repodata/repomd.xml.key")
+ except CreatorError:
+ repokey = None
+ msger.debug("\ncan't get %s/%s" % (baseurl, "repodata/repomd.xml.key"))
+
+ my_repo_metadata.append({"name":reponame,
+ "baseurl":baseurl,
+ "repomd":repomd,
+ "primary":filepaths['primary'],
+ "cachedir":cachedir,
+ "proxies":proxies,
+ "patterns":filepaths['patterns'],
+ "comps":filepaths['comps'],
+ "repokey":repokey,
+ "priority":repo.priority})
+
+ return my_repo_metadata
+
+def get_rpmver_in_repo(repometadata):
+ for repo in repometadata:
+ if repo["primary"].endswith(".xml"):
+ root = xmlparse(repo["primary"])
+ ns = root.getroot().tag
+ ns = ns[0:ns.rindex("}")+1]
+
+ versionlist = []
+ for elm in root.getiterator("%spackage" % ns):
+ if elm.find("%sname" % ns).text == 'rpm':
+ for node in elm.getchildren():
+ if node.tag == "%sversion" % ns:
+ versionlist.append(node.attrib['ver'])
+
+ if versionlist:
+ return reversed(
+ sorted(
+ versionlist,
+ key = lambda ver: map(int, ver.split('.')))).next()
+
+ elif repo["primary"].endswith(".sqlite"):
+ con = sqlite.connect(repo["primary"])
+ for row in con.execute("select version from packages where "
+ "name=\"rpm\" ORDER by version DESC"):
+ con.close()
+ return row[0]
+
+ return None
+
+def get_arch(repometadata):
+ archlist = []
+ for repo in repometadata:
+ if repo["primary"].endswith(".xml"):
+ root = xmlparse(repo["primary"])
+ ns = root.getroot().tag
+ ns = ns[0:ns.rindex("}")+1]
+ for elm in root.getiterator("%spackage" % ns):
+ if elm.find("%sarch" % ns).text not in ("noarch", "src"):
+ arch = elm.find("%sarch" % ns).text
+ if arch not in archlist:
+ archlist.append(arch)
+ elif repo["primary"].endswith(".sqlite"):
+ con = sqlite.connect(repo["primary"])
+ for row in con.execute("select arch from packages where arch not in (\"src\", \"noarch\")"):
+ if row[0] not in archlist:
+ archlist.append(row[0])
+
+ con.close()
+
+ uniq_arch = []
+ for i in range(len(archlist)):
+ if archlist[i] not in rpmmisc.archPolicies.keys():
+ continue
+ need_append = True
+ j = 0
+ while j < len(uniq_arch):
+ if archlist[i] in rpmmisc.archPolicies[uniq_arch[j]].split(':'):
+ need_append = False
+ break
+ if uniq_arch[j] in rpmmisc.archPolicies[archlist[i]].split(':'):
+ if need_append:
+ uniq_arch[j] = archlist[i]
+ need_append = False
+ else:
+ uniq_arch.remove(uniq_arch[j])
+ continue
+ j += 1
+ if need_append:
+ uniq_arch.append(archlist[i])
+
+ return uniq_arch, archlist
+
+def get_package(pkg, repometadata, arch = None):
+ ver = ""
+ priority = 99
+ target_repo = None
+ if not arch:
+ arches = []
+ elif arch not in rpmmisc.archPolicies:
+ arches = [arch]
+ else:
+ arches = rpmmisc.archPolicies[arch].split(':')
+ arches.append('noarch')
+
+ for repo in repometadata:
+ if repo["primary"].endswith(".xml"):
+ root = xmlparse(repo["primary"])
+ ns = root.getroot().tag
+ ns = ns[0:ns.rindex("}")+1]
+ for elm in root.getiterator("%spackage" % ns):
+ if elm.find("%sname" % ns).text == pkg and 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:
+ ver = tmpver
+ location = elm.find("%slocation" % ns)
+ pkgpath = "%s" % location.attrib['href']
+ target_repo = repo
+ break
+ if repo["primary"].endswith(".sqlite"):
+ con = sqlite.connect(repo["primary"])
+ if arch:
+ sql = 'select version, release, location_href from packages ' \
+ 'where name = "%s" and arch IN ("%s")' % \
+ (pkg, '","'.join(arches))
+ for row in con.execute(sql):
+ tmpver = "%s-%s" % (row[0], row[1])
+ if tmpver > ver:
+ ver = tmpver
+ pkgpath = "%s" % row[2]
+ target_repo = repo
+ break
+ else:
+ sql = 'select version, release, location_href from packages ' \
+ 'where name = "%s"' % pkg
+ for row in con.execute(sql):
+ tmpver = "%s-%s" % (row[0], row[1])
+ if tmpver > ver:
+ ver = tmpver
+ pkgpath = "%s" % row[2]
+ target_repo = repo
+ break
+ con.close()
+ if target_repo:
+ makedirs("%s/packages/%s" % (target_repo["cachedir"], target_repo["name"]))
+ url = target_repo["baseurl"].join(pkgpath)
+ filename = str("%s/packages/%s/%s" % (target_repo["cachedir"], target_repo["name"], os.path.basename(pkgpath)))
+ if os.path.exists(filename):
+ ret = rpmmisc.checkRpmIntegrity('rpm', filename)
+ if ret == 0:
+ return filename
+
+ msger.warning("package %s is damaged: %s" %
+ (os.path.basename(filename), filename))
+ os.unlink(filename)
+
+ pkg = myurlgrab(url.full, filename, target_repo["proxies"])
+ return pkg
+ else:
+ return None
+
+def get_source_name(pkg, repometadata):
+
+ def get_bin_name(pkg):
+ m = RPM_RE.match(pkg)
+ if m:
+ return m.group(1)
+ return None
+
+ def get_src_name(srpm):
+ m = SRPM_RE.match(srpm)
+ if m:
+ return m.group(1)
+ return None
+
+ ver = ""
+ target_repo = None
+
+ pkg_name = get_bin_name(pkg)
+ if not pkg_name:
+ return None
+
+ for repo in repometadata:
+ if repo["primary"].endswith(".xml"):
+ root = xmlparse(repo["primary"])
+ ns = root.getroot().tag
+ ns = ns[0:ns.rindex("}")+1]
+ for elm in root.getiterator("%spackage" % ns):
+ if elm.find("%sname" % ns).text == pkg_name:
+ if elm.find("%sarch" % ns).text != "src":
+ version = elm.find("%sversion" % ns)
+ tmpver = "%s-%s" % (version.attrib['ver'], version.attrib['rel'])
+ if tmpver > ver:
+ ver = tmpver
+ fmt = elm.find("%sformat" % ns)
+ if fmt:
+ fns = fmt.getchildren()[0].tag
+ fns = fns[0:fns.rindex("}")+1]
+ pkgpath = fmt.find("%ssourcerpm" % fns).text
+ target_repo = repo
+ break
+
+ if repo["primary"].endswith(".sqlite"):
+ con = sqlite.connect(repo["primary"])
+ for row in con.execute("select version, release, rpm_sourcerpm from packages where name = \"%s\" and arch != \"src\"" % pkg_name):
+ tmpver = "%s-%s" % (row[0], row[1])
+ if tmpver > ver:
+ pkgpath = "%s" % row[2]
+ target_repo = repo
+ break
+ con.close()
+ if target_repo:
+ return get_src_name(pkgpath)
+ else:
+ return None
+
+def get_pkglist_in_patterns(group, patterns):
+ found = False
+ pkglist = []
+ try:
+ root = xmlparse(patterns)
+ except SyntaxError:
+ raise SyntaxError("%s syntax error." % patterns)
+
+ for elm in list(root.getroot()):
+ ns = elm.tag
+ ns = ns[0:ns.rindex("}")+1]
+ name = elm.find("%sname" % ns)
+ summary = elm.find("%ssummary" % ns)
+ if name.text == group or summary.text == group:
+ found = True
+ break
+
+ if not found:
+ return pkglist
+
+ found = False
+ for requires in list(elm):
+ if requires.tag.endswith("requires"):
+ found = True
+ break
+
+ if not found:
+ return pkglist
+
+ for pkg in list(requires):
+ pkgname = pkg.attrib["name"]
+ if pkgname not in pkglist:
+ pkglist.append(pkgname)
+
+ return pkglist
+
+def get_pkglist_in_comps(group, comps):
+ found = False
+ pkglist = []
+ try:
+ root = xmlparse(comps)
+ except SyntaxError:
+ raise SyntaxError("%s syntax error." % comps)
+
+ for elm in root.getiterator("group"):
+ id = elm.find("id")
+ name = elm.find("name")
+ if id.text == group or name.text == group:
+ packagelist = elm.find("packagelist")
+ found = True
+ break
+
+ if not found:
+ return pkglist
+
+ for require in elm.getiterator("packagereq"):
+ if require.tag.endswith("packagereq"):
+ pkgname = require.text
+ if pkgname not in pkglist:
+ pkglist.append(pkgname)
+
+ return pkglist
+
+def is_statically_linked(binary):
+ return ", statically linked, " in runner.outs(['file', binary])
+
+def get_qemu_arm_binary(arch):
+ if arch == "aarch64":
+ node = "/proc/sys/fs/binfmt_misc/aarch64"
+ if os.path.exists("/usr/bin/qemu-arm64") and is_statically_linked("/usr/bin/qemu-arm64"):
+ arm_binary = "qemu-arm64"
+ elif os.path.exists("/usr/bin/qemu-aarch64") and is_statically_linked("/usr/bin/qemu-aarch64"):
+ arm_binary = "qemu-aarch64"
+ elif os.path.exists("/usr/bin/qemu-arm64-static"):
+ arm_binary = "qemu-arm64-static"
+ elif os.path.exists("/usr/bin/qemu-aarch64-static"):
+ arm_binary = "qemu-aarch64-static"
+ else:
+ raise CreatorError("Please install a statically-linked %s" % arm_binary)
+ elif arch == "mipsel":
+ node = "/proc/sys/fs/binfmt_misc/mipsel"
+ arm_binary = "qemu-mipsel"
+ if not os.path.exists("/usr/bin/%s" % arm_binary) or not is_statically_linked("/usr/bin/%s"):
+ arm_binary = "qemu-mipsel-static"
+ if not os.path.exists("/usr/bin/%s" % arm_binary):
+ raise CreatorError("Please install a statically-linked %s" % arm_binary)
+ elif arch == "riscv64":
+ node = "/proc/sys/fs/binfmt_misc/riscv64"
+ arm_binary = "qemu-riscv64"
+ if os.path.exists("/usr/bin/qemu-riscv64") and is_statically_linked("/usr/bin/qemu-riscv64"):
+ arm_binary = "qemu-riscv64"
+ elif os.path.exists("/usr/bin/qemu-riscv64-static"):
+ arm_binary = "qemu-riscv64-static"
+ else:
+ raise CreatorError("Please install a statically-linked %s" % arm_binary)
+ else:
+ node = "/proc/sys/fs/binfmt_misc/arm"
+ arm_binary = "qemu-arm"
+ if not os.path.exists("/usr/bin/qemu-arm") or not is_statically_linked("/usr/bin/qemu-arm"):
+ arm_binary = "qemu-arm-static"
+ if not os.path.exists("/usr/bin/%s" % arm_binary):
+ raise CreatorError("Please install a statically-linked %s" % arm_binary)
+
+ return (arm_binary, node)
+
+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")
+ runner.show([modprobecmd, "binfmt_misc"])
+ if not os.path.exists("/proc/sys/fs/binfmt_misc/register"):
+ mountcmd = find_binary_path("mount")
+ runner.show([mountcmd, "-t", "binfmt_misc", "none", "/proc/sys/fs/binfmt_misc"])
+
+ # qemu_emulator is a special case, we can't use find_binary_path
+ # qemu emulator should be a statically-linked executable file
+ arm_binary, node = get_qemu_arm_binary(arch)
+ qemu_emulator = "/usr/bin/%s" % arm_binary
+
+ 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"])
+
+ # register qemu emulator for interpreting other arch executable file
+ if not os.path.exists(node):
+ if arch == "aarch64":
+ qemu_arm_string = ":aarch64:M::\\x7fELF\\x02\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\xb7:\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xfe\\xff\\xff:%s:\n" % qemu_emulator
+ elif arch == "mipsel":
+ 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
+ elif arch == "riscv64":
+ qemu_arm_string = ":riscv64:M::\\x7fELF\\x02\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\xf3\\x00:\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\\xff\\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)
+ 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):
+ src_repometadata=[]
+ for repo in repometadata:
+ if repo["name"].endswith("-source"):
+ src_repometadata.append(repo)
+ if src_repometadata:
+ return src_repometadata
+ return None
+
+ def get_src_name(srpm):
+ m = SRPM_RE.match(srpm)
+ if m:
+ return m.group(1)
+ return None
+
+ src_repometadata = get_source_repometadata(repometadata)
+
+ if not src_repometadata:
+ msger.warning("No source repo found")
+ return None
+
+ src_pkgs = []
+ lpkgs_dict = {}
+ lpkgs_path = []
+ for repo in src_repometadata:
+ cachepath = "%s/%s/packages/*.src.rpm" %(cachedir, repo["name"])
+ lpkgs_path += glob.glob(cachepath)
+
+ for lpkg in lpkgs_path:
+ lpkg_name = get_src_name(os.path.basename(lpkg))
+ lpkgs_dict[lpkg_name] = lpkg
+ localpkgs = lpkgs_dict.keys()
+
+ cached_count = 0
+ destdir = instroot+'/usr/src/SRPMS'
+ if not os.path.exists(destdir):
+ os.makedirs(destdir)
+
+ srcpkgset = set()
+ for _pkg in pkgs:
+ srcpkg_name = get_source_name(_pkg, repometadata)
+ if not srcpkg_name:
+ continue
+ srcpkgset.add(srcpkg_name)
+
+ for pkg in list(srcpkgset):
+ if pkg in localpkgs:
+ cached_count += 1
+ shutil.copy(lpkgs_dict[pkg], destdir)
+ src_pkgs.append(os.path.basename(lpkgs_dict[pkg]))
+ else:
+ src_pkg = get_package(pkg, src_repometadata, 'src')
+ if src_pkg:
+ shutil.copy(src_pkg, destdir)
+ src_pkgs.append(src_pkg)
+ msger.info("%d source packages gotten from cache" % cached_count)
+
+ return src_pkgs
+
+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
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2009, 2010, 2011 Intel, Inc.
+# Copyright (c) 2007, 2008 Red Hat, Inc.
+# Copyright (c) 2008 Daniel P. Berrange
+# Copyright (c) 2008 David P. Huff
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+
+from mic import msger
+from mic.utils import runner
+from mic.utils.errors import MountError, CreatorError
+from mic.utils.fs_related import *
+from mic.utils.gpt_parser import GptParser
+
+# Overhead of the MBR partitioning scheme (just one sector)
+MBR_OVERHEAD = 1
+# Overhead of the GPT partitioning scheme
+GPT_OVERHEAD = 34
+
+# Size of a sector in bytes
+SECTOR_SIZE = 512
+
+def resolve_ref(ref):
+ real = os.readlink(ref)
+ if not real.startswith('/'):
+ return os.path.realpath(os.path.join(ref, real))
+ else:
+ return real
+
+class PartitionedMount(Mount):
+ def __init__(self, mountdir, skipformat = False):
+ Mount.__init__(self, mountdir)
+ self.disks = {}
+ self.partitions = []
+ self.subvolumes = []
+ self.mapped = False
+ self.mount_order = []
+ self.unmount_order = []
+ self.parted = find_binary_path("parted")
+ self.kpartx = find_binary_path("kpartx")
+ self.mkswap = find_binary_path("mkswap")
+ self.dmsetup = find_binary_path("dmsetup")
+ self.btrfscmd = None
+ self.mountcmd = find_binary_path("mount")
+ self.umountcmd = find_binary_path("umount")
+ self.skipformat = skipformat
+ self.snapshot_created = self.skipformat
+ # Size of a sector used in calculations
+ self.sector_size = SECTOR_SIZE
+ self._partitions_layed_out = False
+
+ def __add_disk(self, disk_name):
+ """ Add a disk 'disk_name' to the internal list of disks. Note,
+ 'disk_name' is the name of the disk in the target system
+ (e.g., sdb). """
+
+ if disk_name in self.disks:
+ # We already have this disk
+ return
+
+ assert not self._partitions_layed_out
+
+ self.disks[disk_name] = \
+ { 'disk': None, # Disk object
+ 'mapped': False, # True if kpartx mapping exists
+ 'numpart': 0, # Number of allocate partitions
+ 'partitions': [], # Indexes to self.partitions
+ 'offset': 0, # Offset of next partition (in sectors)
+ # Minimum required disk size to fit all partitions (in bytes)
+ 'min_size': 0,
+ 'ptable_format': "msdos" } # Partition table format
+
+ def add_disk(self, disk_name, disk_obj):
+ """ Add a disk object which have to be partitioned. More than one disk
+ can be added. In case of multiple disks, disk partitions have to be
+ added for each disk separately with 'add_partition()". """
+
+ self.__add_disk(disk_name)
+ self.disks[disk_name]['disk'] = disk_obj
+
+ def __add_partition(self, part):
+ """ This is a helper function for 'add_partition()' which adds a
+ partition to the internal list of partitions. """
+
+ assert not self._partitions_layed_out
+
+ self.partitions.append(part)
+ self.__add_disk(part['disk_name'])
+
+ def add_partition(self, size, disk_name, mountpoint, fstype = None,
+ label=None, fsopts = None, boot = False, align = None,
+ part_type = None):
+ """ Add the next partition. Partitions have to be added in the
+ first-to-last order. """
+
+ ks_pnum = len(self.partitions)
+
+ # Converting MB to sectors for parted
+ size = size * 1024 * 1024 / self.sector_size
+
+ # We need to handle subvolumes for btrfs
+ if fstype == "btrfs" and fsopts and fsopts.find("subvol=") != -1:
+ self.btrfscmd = find_binary_path("btrfs")
+ subvol = None
+ opts = fsopts.split(",")
+ for opt in opts:
+ if opt.find("subvol=") != -1:
+ subvol = opt.replace("subvol=", "").strip()
+ break
+ if not subvol:
+ raise MountError("No subvolume: %s" % fsopts)
+ self.subvolumes.append({'size': size, # In sectors
+ 'mountpoint': mountpoint, # Mount relative to chroot
+ 'fstype': fstype, # Filesystem type
+ 'fsopts': fsopts, # Filesystem mount options
+ 'disk_name': disk_name, # physical disk name holding partition
+ 'device': None, # kpartx device node for partition
+ 'mapper_device': None, # mapper device node
+ 'mpath_device': None, # multipath device of device mapper
+ 'mount': None, # Mount object
+ 'subvol': subvol, # Subvolume name
+ 'boot': boot, # Bootable flag
+ 'mounted': False # Mount flag
+ })
+
+ # We still need partition for "/" or non-subvolume
+ if mountpoint == "/" or not fsopts or fsopts.find("subvol=") == -1:
+ # Don't need subvolume for "/" because it will be set as default subvolume
+ if fsopts and fsopts.find("subvol=") != -1:
+ opts = fsopts.split(",")
+ for opt in opts:
+ if opt.strip().startswith("subvol="):
+ opts.remove(opt)
+ break
+ fsopts = ",".join(opts)
+
+ part = { 'ks_pnum' : ks_pnum, # Partition number in the KS file
+ 'size': size, # In sectors
+ 'mountpoint': mountpoint, # Mount relative to chroot
+ 'fstype': fstype, # Filesystem type
+ 'fsopts': fsopts, # Filesystem mount options
+ 'label': label, # Partition label
+ 'disk_name': disk_name, # physical disk name holding partition
+ 'device': None, # kpartx device node for partition
+ 'mapper_device': None, # mapper device node
+ 'mpath_device': None, # multipath device of device mapper
+ 'mount': None, # Mount object
+ 'num': None, # Partition number
+ 'boot': boot, # Bootable flag
+ 'align': align, # Partition alignment
+ 'part_type' : part_type, # Partition type
+ 'uuid': None, # Partition UUID (no-GPT use)
+ 'partuuid': None } # Partition UUID (GPT-only)
+
+ self.__add_partition(part)
+
+ def layout_partitions(self, ptable_format = "msdos"):
+ """ Layout the partitions, meaning calculate the position of every
+ partition on the disk. The 'ptable_format' parameter defines the
+ partition table format, and may be either "msdos" or "gpt". """
+
+ msger.debug("Assigning %s partitions to disks" % ptable_format)
+
+ if ptable_format not in ('msdos', 'gpt'):
+ raise MountError("Unknown partition table format '%s', supported " \
+ "formats are: 'msdos' and 'gpt'" % ptable_format)
+
+ if self._partitions_layed_out:
+ return
+
+ self._partitions_layed_out = True
+
+ # Go through partitions in the order they are added in .ks file
+ for n in range(len(self.partitions)):
+ p = self.partitions[n]
+
+ if not self.disks.has_key(p['disk_name']):
+ raise MountError("No disk %s for partition %s" \
+ % (p['disk_name'], p['mountpoint']))
+
+ if p['part_type'] and ptable_format != 'gpt':
+ # The --part-type can also be implemented for MBR partitions,
+ # in which case it would map to the 1-byte "partition type"
+ # filed at offset 3 of the partition entry.
+ raise MountError("setting custom partition type is only " \
+ "implemented for GPT partitions")
+
+ # Get the disk where the partition is located
+ d = self.disks[p['disk_name']]
+ d['numpart'] += 1
+ d['ptable_format'] = ptable_format
+
+ if d['numpart'] == 1:
+ if ptable_format == "msdos":
+ overhead = MBR_OVERHEAD
+ else:
+ overhead = GPT_OVERHEAD
+
+ # Skip one sector required for the partitioning scheme overhead
+ d['offset'] += overhead
+ # Steal few sectors from the first partition to offset for the
+ # partitioning overhead
+ p['size'] -= overhead
+
+ if p['align']:
+ # If not first partition and we do have alignment set we need
+ # to align the partition.
+ # FIXME: This leaves a empty spaces to the disk. To fill the
+ # gaps we could enlarge the previous partition?
+
+ # Calc how much the alignment is off.
+ align_sectors = d['offset'] % (p['align'] * 1024 / self.sector_size)
+ # We need to move forward to the next alignment point
+ align_sectors = (p['align'] * 1024 / self.sector_size) - align_sectors
+
+ msger.debug("Realignment for %s%s with %s sectors, original"
+ " offset %s, target alignment is %sK." %
+ (p['disk_name'], d['numpart'], align_sectors,
+ d['offset'], p['align']))
+
+ # increase the offset so we actually start the partition on right alignment
+ d['offset'] += align_sectors
+
+ p['start'] = d['offset']
+ d['offset'] += p['size']
+
+ p['type'] = 'primary'
+ p['num'] = d['numpart']
+
+ if d['ptable_format'] == "msdos":
+ if d['numpart'] > 2:
+ # Every logical partition requires an additional sector for
+ # the EBR, so steal the last sector from the end of each
+ # partition starting from the 3rd one for the EBR. This
+ # will make sure the logical partitions are aligned
+ # correctly.
+ p['size'] -= 1
+
+ if d['numpart'] > 3:
+ p['type'] = 'logical'
+ p['num'] = d['numpart'] + 1
+
+ d['partitions'].append(n)
+ msger.debug("Assigned %s to %s%d, sectors range %d-%d size %d "
+ "sectors (%d bytes)." \
+ % (p['mountpoint'], p['disk_name'], p['num'],
+ p['start'], p['start'] + p['size'] - 1,
+ p['size'], p['size'] * self.sector_size))
+
+ # Once all the partitions have been laid out, we can calculate the
+ # minimum disk sizes.
+ for disk_name, d in self.disks.items():
+ d['min_size'] = d['offset']
+ if d['ptable_format'] == 'gpt':
+ # Account for the backup partition table at the end of the disk
+ d['min_size'] += GPT_OVERHEAD
+
+ d['min_size'] *= self.sector_size
+
+ def __run_parted(self, args):
+ """ Run parted with arguments specified in the 'args' list. """
+
+ args.insert(0, self.parted)
+ msger.debug(args)
+
+ rc, out = runner.runtool(args, catch = 3)
+ out = out.strip()
+ msger.debug("'parted': exitcode: %d, output: %s" % (rc, out))
+ # We don't throw exception when return code is not 0, because
+ # parted always fails to reload part table with loop devices. This
+ # prevents us from distinguishing real errors based on return
+ # code.
+ return rc, out
+
+ def __create_partition(self, device, parttype, fstype, start, size):
+ """ Create a partition on an image described by the 'device' object. """
+
+ # Start is included to the size so we need to subtract one from the end.
+ end = start + size - 1
+ msger.debug("Added '%s' partition, sectors %d-%d, size %d sectors" %
+ (parttype, start, end, size))
+
+ args = ["-s", device, "unit", "s", "mkpart", parttype]
+ if fstype:
+ args.extend([fstype])
+ args.extend(["%d" % start, "%d" % end])
+
+ return self.__run_parted(args)
+
+ def __format_disks(self):
+ self.layout_partitions()
+
+ if self.skipformat:
+ msger.debug("Skipping disk format, because skipformat flag is set.")
+ return
+
+ for dev in self.disks.keys():
+ d = self.disks[dev]
+ msger.debug("Initializing partition table for %s" % \
+ (d['disk'].device))
+ self.__run_parted(["-s", d['disk'].device, "mklabel",
+ d['ptable_format']])
+
+ msger.debug("Creating partitions")
+
+ for p in self.partitions:
+ d = self.disks[p['disk_name']]
+ if d['ptable_format'] == "msdos" and p['num'] == 5:
+ # The last sector of the 3rd partition was reserved for the EBR
+ # of the first _logical_ partition. This is why the extended
+ # partition should start one sector before the first logical
+ # partition.
+ self.__create_partition(d['disk'].device, "extended",
+ None, p['start'] - 1,
+ d['offset'] - p['start'])
+
+ if p['fstype'] == "swap":
+ parted_fs_type = "linux-swap"
+ elif p['fstype'] == "vfat":
+ parted_fs_type = "fat32"
+ elif p['fstype'] == "msdos":
+ parted_fs_type = "fat16"
+ else:
+ # Type for ext2/ext3/ext4/btrfs
+ parted_fs_type = "ext2"
+
+ # Boot ROM of OMAP boards require vfat boot partition to have an
+ # even number of sectors.
+ if p['mountpoint'] == "/boot" and p['fstype'] in ["vfat", "msdos"] \
+ and p['size'] % 2:
+ msger.debug("Substracting one sector from '%s' partition to " \
+ "get even number of sectors for the partition" % \
+ p['mountpoint'])
+ p['size'] -= 1
+
+ self.__create_partition(d['disk'].device, p['type'],
+ parted_fs_type, p['start'], p['size'])
+
+ if p['boot']:
+ if d['ptable_format'] == 'gpt':
+ flag_name = "legacy_boot"
+ else:
+ flag_name = "boot"
+ msger.debug("Set '%s' flag for partition '%s' on disk '%s'" % \
+ (flag_name, p['num'], d['disk'].device))
+ cmd = ["-s", d['disk'].device,
+ "set", "%d" % p['num'],
+ flag_name, "on"]
+ exitcode, output = self.__run_parted(cmd)
+ if exitcode != 0:
+ msger.warning(
+ "partition '%s' is marked with --active, "
+ "but flag '%s' can't be set: "
+ "exitcode: %s, output: %s"
+ % (p['mountpoint'], flag_name, exitcode, output))
+
+ # If the partition table format is "gpt", find out PARTUUIDs for all
+ # the partitions. And if users specified custom parition type UUIDs,
+ # set them.
+ for disk_name, disk in self.disks.items():
+ if disk['ptable_format'] != 'gpt':
+ continue
+
+ pnum = 0
+ gpt_parser = GptParser(disk['disk'].device, SECTOR_SIZE)
+ # Iterate over all GPT partitions on this disk
+ for entry in gpt_parser.get_partitions():
+ pnum += 1
+ # Find the matching partition in the 'self.partitions' list
+ for n in disk['partitions']:
+ p = self.partitions[n]
+ if p['num'] == pnum:
+ # Found, fetch PARTUUID (partition's unique ID)
+ p['partuuid'] = entry['part_uuid']
+ msger.debug("PARTUUID for partition %d on disk '%s' " \
+ "(mount point '%s') is '%s'" % (pnum, \
+ disk_name, p['mountpoint'], p['partuuid']))
+ if p['part_type']:
+ entry['type_uuid'] = p['part_type']
+ msger.debug("Change type of partition %d on disk " \
+ "'%s' (mount point '%s') to '%s'" % \
+ (pnum, disk_name, p['mountpoint'],
+ p['part_type']))
+ gpt_parser.change_partition(entry)
+
+ del gpt_parser
+
+ def __map_partitions(self):
+ """Load it if dm_snapshot isn't loaded. """
+ load_module("dm_snapshot")
+
+ for dev in self.disks.keys():
+ d = self.disks[dev]
+ if d['mapped']:
+ continue
+
+ msger.debug("Running kpartx on %s" % d['disk'].device )
+ rc, kpartx_output = runner.runtool([self.kpartx, "-l", "-v", d['disk'].device])
+ kpartx_output = kpartx_output.splitlines()
+
+ if rc != 0:
+ raise MountError("Failed to query partition mapping for '%s'" %
+ d['disk'].device)
+
+ # Strip trailing blank and mask verbose output
+ i = 0
+ while i < len(kpartx_output) and kpartx_output[i][0:4] != "loop":
+ i = i + 1
+ kpartx_output = kpartx_output[i:]
+
+ # Make sure kpartx reported the right count of partitions
+ if len(kpartx_output) != d['numpart']:
+ # If this disk has more than 3 partitions, then in case of MBR
+ # paritions there is an extended parition. Different versions
+ # of kpartx behave differently WRT the extended partition -
+ # some map it, some ignore it. This is why we do the below hack
+ # - if kpartx reported one more partition and the partition
+ # table type is "msdos" and the amount of partitions is more
+ # than 3, we just assume kpartx mapped the extended parition
+ # and we remove it.
+ if len(kpartx_output) == d['numpart'] + 1 \
+ and d['ptable_format'] == 'msdos' and len(kpartx_output) > 3:
+ kpartx_output.pop(3)
+ else:
+ raise MountError("Unexpected number of partitions from " \
+ "kpartx: %d != %d" % \
+ (len(kpartx_output), d['numpart']))
+
+ for i in range(len(kpartx_output)):
+ line = kpartx_output[i]
+ newdev = line.split()[0]
+ mapperdev = "/dev/mapper/" + newdev
+ loopdev = d['disk'].device + newdev[-1]
+
+ msger.debug("Dev %s: %s -> %s" % (newdev, loopdev, mapperdev))
+ pnum = d['partitions'][i]
+ self.partitions[pnum]['device'] = loopdev
+ self.partitions[pnum]['mapper_device'] = mapperdev
+
+ # grub's install wants partitions to be named
+ # to match their parent device + partition num
+ # kpartx doesn't work like this, so we add compat
+ # symlinks to point to /dev/mapper
+ if os.path.lexists(loopdev):
+ os.unlink(loopdev)
+ os.symlink(mapperdev, loopdev)
+
+ msger.debug("Adding partx mapping for %s" % d['disk'].device)
+ rc = runner.show([self.kpartx, "-v", "-sa", d['disk'].device])
+
+ if rc != 0:
+ # Make sure that the device maps are also removed on error case.
+ # The d['mapped'] isn't set to True if the kpartx fails so
+ # failed mapping will not be cleaned on cleanup either.
+ runner.quiet([self.kpartx, "-sd", d['disk'].device])
+ raise MountError("Failed to map partitions for '%s'" %
+ d['disk'].device)
+
+ for p in self.partitions:
+ if p['mapper_device'] and os.path.islink(p['mapper_device']):
+ p['mpath_device'] = resolve_ref(p['mapper_device'])
+ else:
+ p['mpath_device'] = ''
+
+ # FIXME: need a better way to fix the latency
+ import time
+ time.sleep(1)
+
+ if not os.path.exists(mapperdev):
+ # load mapper device if not updated
+ runner.quiet([self.dmsetup, "mknodes"])
+ # still not updated, roll back
+ if not os.path.exists(mapperdev):
+ runner.quiet([self.kpartx, "-sd", d['disk'].device])
+ raise MountError("Failed to load mapper devices for '%s'" %
+ d['disk'].device)
+
+ d['mapped'] = True
+
+ def __unmap_partitions(self):
+ for dev in self.disks.keys():
+ d = self.disks[dev]
+ if not d['mapped']:
+ continue
+
+ msger.debug("Removing compat symlinks")
+ for pnum in d['partitions']:
+ if self.partitions[pnum]['device'] != None:
+ os.unlink(self.partitions[pnum]['device'])
+ self.partitions[pnum]['device'] = None
+
+ msger.debug("Unmapping %s" % d['disk'].device)
+ rc = runner.quiet([self.kpartx, "-sd", d['disk'].device])
+ if rc != 0:
+ raise MountError("Failed to unmap partitions for '%s'" %
+ d['disk'].device)
+
+ d['mapped'] = False
+
+ def __calculate_mountorder(self):
+ msger.debug("Calculating mount order")
+ for p in self.partitions:
+ if p['mountpoint']:
+ self.mount_order.append(p['mountpoint'])
+ self.unmount_order.append(p['mountpoint'])
+
+ self.mount_order.sort()
+ self.unmount_order.sort()
+ self.unmount_order.reverse()
+
+ def cleanup(self):
+ Mount.cleanup(self)
+ if self.disks:
+ self.__unmap_partitions()
+ for dev in self.disks.keys():
+ d = self.disks[dev]
+ try:
+ d['disk'].cleanup()
+ except:
+ pass
+
+ def unmount(self):
+ self.__unmount_subvolumes()
+ for mp in self.unmount_order:
+ if mp == 'swap':
+ continue
+ p = None
+ for p1 in self.partitions:
+ if p1['mountpoint'] == mp:
+ p = p1
+ break
+
+ if p['mount'] != None:
+ try:
+ # Create subvolume snapshot here
+ if p['fstype'] == "btrfs" and p['mountpoint'] == "/" and \
+ not self.snapshot_created:
+ self.__create_subvolume_snapshots(p, p["mount"])
+ p['mount'].cleanup()
+ except:
+ pass
+ p['mount'] = None
+
+ # Only for btrfs
+ def __get_subvolume_id(self, rootpath, subvol):
+ if not self.btrfscmd:
+ self.btrfscmd = find_binary_path("btrfs")
+ argv = [ self.btrfscmd, "subvolume", "list", rootpath ]
+
+ rc, out = runner.runtool(argv)
+ msger.debug(out)
+
+ if rc != 0:
+ raise MountError("Failed to get subvolume id from %s',"
+ "return code: %d." % (rootpath, rc))
+
+ subvolid = -1
+ for line in out.splitlines():
+ if line.endswith(" path %s" % subvol):
+ subvolid = line.split()[1]
+ if not subvolid.isdigit():
+ raise MountError("Invalid subvolume id: %s" % subvolid)
+ subvolid = int(subvolid)
+ break
+ return subvolid
+
+ def __create_subvolume_metadata(self, p, pdisk):
+ if len(self.subvolumes) == 0:
+ return
+
+ argv = [ self.btrfscmd, "subvolume", "list", pdisk.mountdir ]
+ rc, out = runner.runtool(argv)
+ msger.debug(out)
+
+ if rc != 0:
+ raise MountError("Failed to get subvolume id from %s', return code: %d." % (pdisk.mountdir, rc))
+
+ subvolid_items = out.splitlines()
+ subvolume_metadata = ""
+ for subvol in self.subvolumes:
+ for line in subvolid_items:
+ if line.endswith(" path %s" % subvol["subvol"]):
+ subvolid = line.split()[1]
+ if not subvolid.isdigit():
+ raise MountError("Invalid subvolume id: %s" % subvolid)
+
+ subvolid = int(subvolid)
+ opts = subvol["fsopts"].split(",")
+ for opt in opts:
+ if opt.strip().startswith("subvol="):
+ opts.remove(opt)
+ break
+ fsopts = ",".join(opts)
+ subvolume_metadata += "%d\t%s\t%s\t%s\n" % (subvolid, subvol["subvol"],
+ subvol['mountpoint'], fsopts)
+
+ if subvolume_metadata:
+ fd = open("%s/.subvolume_metadata" % pdisk.mountdir, "w")
+ fd.write(subvolume_metadata)
+ fd.close()
+
+ def __get_subvolume_metadata(self, p, pdisk):
+ subvolume_metadata_file = "%s/.subvolume_metadata" % pdisk.mountdir
+ if not os.path.exists(subvolume_metadata_file):
+ return
+
+ fd = open(subvolume_metadata_file, "r")
+ content = fd.read()
+ fd.close()
+
+ for line in content.splitlines():
+ items = line.split("\t")
+ if items and len(items) == 4:
+ self.subvolumes.append({'size': 0, # In sectors
+ 'mountpoint': items[2], # Mount relative to chroot
+ 'fstype': "btrfs", # Filesystem type
+ 'fsopts': items[3] + ",subvol=%s" % items[1], # Filesystem mount options
+ 'disk_name': p['disk_name'], # physical disk name holding partition
+ 'device': None, # kpartx device node for partition
+ 'mount': None, # Mount object
+ 'subvol': items[1], # Subvolume name
+ 'boot': False, # Bootable flag
+ 'mounted': False # Mount flag
+ })
+
+ def __create_subvolumes(self, p, pdisk):
+ """ Create all the subvolumes. """
+
+ for subvol in self.subvolumes:
+ argv = [ self.btrfscmd, "subvolume", "create", pdisk.mountdir + "/" + subvol["subvol"]]
+
+ rc = runner.show(argv)
+ if rc != 0:
+ raise MountError("Failed to create subvolume '%s', return code: %d." % (subvol["subvol"], rc))
+
+ # Set default subvolume, subvolume for "/" is default
+ subvol = None
+ for subvolume in self.subvolumes:
+ if subvolume["mountpoint"] == "/" and p['disk_name'] == subvolume['disk_name']:
+ subvol = subvolume
+ break
+
+ if subvol:
+ # Get default subvolume id
+ subvolid = self. __get_subvolume_id(pdisk.mountdir, subvol["subvol"])
+ # Set default subvolume
+ if subvolid != -1:
+ rc = runner.show([ self.btrfscmd, "subvolume", "set-default", "%d" %
+ subvolid, pdisk.mountdir])
+ if rc != 0:
+ raise MountError("Failed to set default subvolume id: %d', return code: %d."
+ % (subvolid, rc))
+
+ self.__create_subvolume_metadata(p, pdisk)
+
+ def __mount_subvolumes(self, p, pdisk):
+ if self.skipformat:
+ # Get subvolume info
+ self.__get_subvolume_metadata(p, pdisk)
+ # Set default mount options
+ if len(self.subvolumes) != 0:
+ for subvol in self.subvolumes:
+ if subvol["mountpoint"] == p["mountpoint"] == "/":
+ opts = subvol["fsopts"].split(",")
+ for opt in opts:
+ if opt.strip().startswith("subvol="):
+ opts.remove(opt)
+ break
+ pdisk.fsopts = ",".join(opts)
+ break
+
+ if len(self.subvolumes) == 0:
+ # Return directly if no subvolumes
+ return
+
+ # Remount to make default subvolume mounted
+ rc = runner.show([self.umountcmd, pdisk.mountdir])
+ if rc != 0:
+ raise MountError("Failed to umount %s" % pdisk.mountdir)
+
+ rc = runner.show([self.mountcmd, "-o", pdisk.fsopts, pdisk.disk.device, pdisk.mountdir])
+ if rc != 0:
+ raise MountError("Failed to umount %s" % pdisk.mountdir)
+
+ for subvol in self.subvolumes:
+ if subvol["mountpoint"] == "/":
+ continue
+ subvolid = self. __get_subvolume_id(pdisk.mountdir, subvol["subvol"])
+ if subvolid == -1:
+ msger.debug("WARNING: invalid subvolume %s" % subvol["subvol"])
+ continue
+ # Replace subvolume name with subvolume ID
+ opts = subvol["fsopts"].split(",")
+ for opt in opts:
+ if opt.strip().startswith("subvol="):
+ opts.remove(opt)
+ break
+
+ opts.extend(["subvolrootid=0", "subvol=%s" % subvol["subvol"]])
+ fsopts = ",".join(opts)
+ subvol['fsopts'] = fsopts
+ mountpoint = self.mountdir + subvol['mountpoint']
+ makedirs(mountpoint)
+ rc = runner.show([self.mountcmd, "-o", fsopts, pdisk.disk.device, mountpoint])
+ if rc != 0:
+ raise MountError("Failed to mount subvolume %s to %s" % (subvol["subvol"], mountpoint))
+ subvol["mounted"] = True
+
+ def __unmount_subvolumes(self):
+ """ It may be called multiple times, so we need to chekc if it is still mounted. """
+ for subvol in self.subvolumes:
+ if subvol["mountpoint"] == "/":
+ continue
+ if not subvol["mounted"]:
+ continue
+ mountpoint = self.mountdir + subvol['mountpoint']
+ rc = runner.show([self.umountcmd, mountpoint])
+ if rc != 0:
+ raise MountError("Failed to unmount subvolume %s from %s" % (subvol["subvol"], mountpoint))
+ subvol["mounted"] = False
+
+ def __create_subvolume_snapshots(self, p, pdisk):
+ import time
+
+ if self.snapshot_created:
+ return
+
+ # Remount with subvolid=0
+ rc = runner.show([self.umountcmd, pdisk.mountdir])
+ if rc != 0:
+ raise MountError("Failed to umount %s" % pdisk.mountdir)
+ if pdisk.fsopts:
+ mountopts = pdisk.fsopts + ",subvolid=0"
+ else:
+ mountopts = "subvolid=0"
+ rc = runner.show([self.mountcmd, "-o", mountopts, pdisk.disk.device, pdisk.mountdir])
+ if rc != 0:
+ raise MountError("Failed to umount %s" % pdisk.mountdir)
+
+ # Create all the subvolume snapshots
+ snapshotts = time.strftime("%Y%m%d-%H%M")
+ for subvol in self.subvolumes:
+ subvolpath = pdisk.mountdir + "/" + subvol["subvol"]
+ snapshotpath = subvolpath + "_%s-1" % snapshotts
+ rc = runner.show([ self.btrfscmd, "subvolume", "snapshot", subvolpath, snapshotpath ])
+ if rc != 0:
+ raise MountError("Failed to create subvolume snapshot '%s' for '%s', return code:"
+ "%d." % (snapshotpath, subvolpath, rc))
+
+ self.snapshot_created = True
+
+ def mount(self):
+ for dev in self.disks.keys():
+ d = self.disks[dev]
+ d['disk'].create()
+
+ self.__format_disks()
+ self.__map_partitions()
+ self.__calculate_mountorder()
+
+ for mp in self.mount_order:
+ p = None
+ for p1 in self.partitions:
+ if p1['mountpoint'] == mp:
+ p = p1
+ break
+
+ if not p['label']:
+ if p['mountpoint'] == "/":
+ p['label'] = 'platform'
+ else:
+ p['label'] = mp.split('/')[-1]
+
+ if mp == 'swap':
+ import uuid
+ p['uuid'] = str(uuid.uuid1())
+ runner.show([self.mkswap,
+ '-L', p['label'],
+ '-U', p['uuid'],
+ p['device']])
+ continue
+
+ rmmountdir = False
+ if p['mountpoint'] == "/":
+ rmmountdir = True
+ if p['fstype'] == "vfat" or p['fstype'] == "msdos":
+ my_disk_mount = VfatDiskMount
+ elif p['fstype'] in ("ext2", "ext3", "ext4"):
+ my_disk_mount = ExtDiskMount
+ elif p['fstype'] == "btrfs":
+ my_disk_mount = BtrfsDiskMount
+ else:
+ raise MountError("Fail to support file system " + p['fstype'])
+
+ if p['fstype'] == "btrfs" and not p['fsopts']:
+ p['fsopts'] = "subvolid=0"
+
+ pdisk = my_disk_mount(RawDisk(p['size'] * self.sector_size, p['device']),
+ self.mountdir + p['mountpoint'],
+ p['fstype'],
+ 4096,
+ p['label'],
+ rmmountdir,
+ self.skipformat,
+ fsopts = p['fsopts'])
+ pdisk.mount(pdisk.fsopts)
+ if p['fstype'] == "btrfs" and p['mountpoint'] == "/":
+ if not self.skipformat:
+ self.__create_subvolumes(p, pdisk)
+ self.__mount_subvolumes(p, pdisk)
+ p['mount'] = pdisk
+ p['uuid'] = pdisk.uuid
+
+ def resparse(self, size = None):
+ # Can't re-sparse a disk image - too hard
+ pass
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2010, 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+import re
+import urlparse
+from mic import msger
+
+_my_proxies = {}
+_my_noproxy = None
+_my_noproxy_list = []
+
+def set_proxy_environ():
+ if not _my_proxies:
+ return
+ for key in _my_proxies.keys():
+ os.environ[key + "_proxy"] = _my_proxies[key]
+ if not _my_noproxy:
+ return
+ os.environ["no_proxy"] = _my_noproxy
+
+def unset_proxy_environ():
+ for env in ('http_proxy',
+ 'https_proxy',
+ 'ftp_proxy',
+ 'all_proxy'):
+ if env in os.environ:
+ del os.environ[env]
+
+ env_upper = env.upper()
+ if env_upper in os.environ:
+ del os.environ[env_upper]
+
+def _set_proxies(proxy = None, no_proxy = None):
+ """Return a dictionary of scheme -> proxy server URL mappings.
+ """
+
+ global _my_noproxy, _my_proxies
+ _my_proxies = {}
+ _my_noproxy = None
+ proxies = []
+ if proxy:
+ proxies.append(("http_proxy", proxy))
+ if no_proxy:
+ proxies.append(("no_proxy", no_proxy))
+
+ # Get proxy settings from environment if not provided
+ if not proxy and not no_proxy:
+ proxies = os.environ.items()
+
+ # Remove proxy env variables, urllib2 can't handle them correctly
+ unset_proxy_environ()
+
+ for name, value in proxies:
+ name = name.lower()
+ if value and name[-6:] == '_proxy':
+ if name[0:2] != "no":
+ _my_proxies[name[:-6]] = value
+ else:
+ _my_noproxy = value
+
+def _ip_to_int(ip):
+ ipint = 0
+ shift = 24
+ for dec in ip.split("."):
+ if not dec.isdigit():
+ continue
+ ipint |= int(dec) << shift
+ shift -= 8
+ return ipint
+
+def _int_to_ip(val):
+ ipaddr = ""
+ shift = 0
+ for i in range(4):
+ dec = val >> shift
+ dec &= 0xff
+ ipaddr = ".%d%s" % (dec, ipaddr)
+ shift += 8
+ return ipaddr[1:]
+
+def _isip(host):
+ if host.replace(".", "").isdigit():
+ return True
+ return False
+
+def _set_noproxy_list():
+ global _my_noproxy, _my_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 as 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:
+ continue
+
+ if item[0] != '.' and item.find("/") == -1:
+ # Need to match it
+ _my_noproxy_list.append({"match":0, "needle":item})
+
+ elif item[0] == '.':
+ # Need to match at tail
+ _my_noproxy_list.append({"match":1, "needle":item})
+
+ elif item.find("/") > 3:
+ # IP/MASK, need to match at head
+ needle = item[0:item.find("/")].strip()
+ ip = _ip_to_int(needle)
+ netmask = 0
+ mask = item[item.find("/")+1:].strip()
+
+ if mask.isdigit():
+ netmask = int(mask)
+ netmask = ~((1<<(32-netmask)) - 1)
+ ip &= netmask
+ else:
+ shift = 24
+ netmask = 0
+ for dec in mask.split("."):
+ if not dec.isdigit():
+ continue
+ netmask |= int(dec) << shift
+ shift -= 8
+ 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]
+ # urlparse.urlparse(url) returns (scheme, host, path, parm, query, frag)
+
+ if '@' in host:
+ user_pass, host = host.split('@', 1)
+
+ if ':' in host:
+ host, port = host.split(':', 1)
+
+ hostisip = _isip(host)
+ for item in _my_noproxy_list:
+ if hostisip and item["match"] == 1:
+ continue
+
+ if item["match"] == 2 and hostisip:
+ if (_ip_to_int(host) & item["netmask"]) == item["needle"]:
+ return True
+
+ if item["match"] == 0:
+ if host == item["needle"]:
+ return True
+
+ if item["match"] == 1:
+ if re.match(r".*%s$" % item["needle"], host):
+ return True
+
+ return False
+
+def set_proxies(proxy = None, no_proxy = None):
+ _set_proxies(proxy, no_proxy)
+ _set_noproxy_list()
+ set_proxy_environ()
+
+def get_proxy_for(url):
+ if url.startswith('file:') or _isnoproxy(url):
+ return None
+
+ type = url[0:url.index(":")]
+ proxy = None
+ if _my_proxies.has_key(type):
+ proxy = _my_proxies[type]
+ elif _my_proxies.has_key("http"):
+ proxy = _my_proxies["http"]
+ else:
+ proxy = None
+
+ return proxy
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2008, 2009, 2010, 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+import sys
+import re
+import rpm
+
+from mic import msger
+from mic.utils.errors import CreatorError
+from mic.utils.proxy import get_proxy_for
+from mic.utils import runner
+
+
+class RPMInstallCallback:
+ """ Command line callback class for callbacks from the RPM library.
+ """
+
+ def __init__(self, ts, output=1):
+ self.output = output
+ self.callbackfilehandles = {}
+ self.total_actions = 0
+ self.total_installed = 0
+ self.total_installing = 0
+ self.installed_pkg_names = []
+ self.total_removed = 0
+ self.mark = "+"
+ self.marks = 40
+ self.lastmsg = None
+ self.tsInfo = None # this needs to be set for anything else to work
+ self.ts = ts
+ self.filelog = False
+ self.logString = []
+ self.headmsg = "Installing"
+
+ def _dopkgtup(self, hdr):
+ tmpepoch = hdr['epoch']
+ if tmpepoch is None: epoch = '0'
+ else: epoch = str(tmpepoch)
+
+ return (hdr['name'], hdr['arch'], epoch, hdr['version'], hdr['release'])
+
+ def _makeHandle(self, hdr):
+ handle = '%s:%s.%s-%s-%s' % (hdr['epoch'], hdr['name'], hdr['version'],
+ hdr['release'], hdr['arch'])
+
+ return handle
+
+ def _localprint(self, msg):
+ if self.output:
+ msger.info(msg)
+
+ def _makefmt(self, percent, progress = True):
+ l = len(str(self.total_actions))
+ size = "%s.%s" % (l, l)
+ fmt_done = "[%" + size + "s/%" + size + "s]"
+ done = fmt_done % (self.total_installing,
+ self.total_actions)
+ marks = self.marks - (2 * l)
+ width = "%s.%s" % (marks, marks)
+ fmt_bar = "%-" + width + "s"
+ if progress:
+ bar = fmt_bar % (self.mark * int(marks * (percent / 100.0)), )
+ fmt = "%-10.10s: %-50.50s " + bar + " " + done
+ else:
+ bar = fmt_bar % (self.mark * marks, )
+ fmt = "%-10.10s: %-50.50s " + bar + " " + done
+ return fmt
+
+ def _logPkgString(self, hdr):
+ """return nice representation of the package for the log"""
+ (n,a,e,v,r) = self._dopkgtup(hdr)
+ if e == '0':
+ pkg = '%s.%s %s-%s' % (n, a, v, r)
+ else:
+ pkg = '%s.%s %s:%s-%s' % (n, a, e, v, r)
+
+ return pkg
+
+ def callback(self, what, bytes, total, h, user):
+ if what == rpm.RPMCALLBACK_TRANS_START:
+ if bytes == 6:
+ self.total_actions = total
+
+ elif what == rpm.RPMCALLBACK_TRANS_PROGRESS:
+ pass
+
+ elif what == rpm.RPMCALLBACK_TRANS_STOP:
+ pass
+
+ elif what == rpm.RPMCALLBACK_INST_OPEN_FILE:
+ self.lastmsg = None
+ hdr = None
+ if h is not None:
+ try:
+ hdr, rpmloc = h
+ except:
+ 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
+ if hdr['name'] not in self.installed_pkg_names:
+ self.installed_pkg_names.append(hdr['name'])
+ self.total_installed += 1
+ return fd
+ else:
+ self._localprint("No header - huh?")
+
+ elif what == rpm.RPMCALLBACK_INST_CLOSE_FILE:
+ hdr = None
+ if h is not None:
+ try:
+ hdr, rpmloc = h
+ except:
+ rpmloc = h
+ hdr = readRpmHeader(self.ts, h)
+
+ handle = self._makeHandle(hdr)
+ os.close(self.callbackfilehandles[handle])
+ fd = 0
+
+ # log stuff
+ #pkgtup = self._dopkgtup(hdr)
+ self.logString.append(self._logPkgString(hdr))
+
+ elif what == rpm.RPMCALLBACK_INST_START:
+ self.total_installing += 1
+
+ elif what == rpm.RPMCALLBACK_UNINST_STOP:
+ pass
+
+ elif what == rpm.RPMCALLBACK_INST_PROGRESS:
+ if h is not None:
+ percent = (self.total_installed*100)/self.total_actions
+ if total > 0:
+ 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)
+ if self.output:
+ fmt = self._makefmt(percent)
+ msg = fmt % (self.headmsg, pkgname)
+ if msg != self.lastmsg:
+ self.lastmsg = msg
+
+ msger.info(msg)
+
+ if self.total_installed == self.total_actions:
+ msger.raw('')
+ msger.verbose('\n'.join(self.logString))
+
+ elif what == rpm.RPMCALLBACK_UNINST_START:
+ pass
+
+ elif what == rpm.RPMCALLBACK_UNINST_PROGRESS:
+ pass
+
+ elif what == rpm.RPMCALLBACK_UNINST_STOP:
+ self.total_removed += 1
+
+ elif what == rpm.RPMCALLBACK_REPACKAGE_START:
+ pass
+
+ elif what == rpm.RPMCALLBACK_REPACKAGE_STOP:
+ pass
+
+ 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. """
+
+ fd = os.open(filename, os.O_RDONLY)
+ h = ts.hdrFromFdno(fd)
+ os.close(fd)
+ return h
+
+def splitFilename(filename):
+ """ Pass in a standard style rpm fullname
+
+ Return a name, version, release, epoch, arch, e.g.::
+ foo-1.0-1.i386.rpm returns foo, 1.0, 1, i386
+ 1:bar-9-123a.ia64.rpm returns bar, 9, 123a, 1, ia64
+ """
+
+ if filename[-4:] == '.rpm':
+ filename = filename[:-4]
+
+ archIndex = filename.rfind('.')
+ arch = filename[archIndex+1:]
+
+ relIndex = filename[:archIndex].rfind('-')
+ rel = filename[relIndex+1:archIndex]
+
+ verIndex = filename[:relIndex].rfind('-')
+ ver = filename[verIndex+1:relIndex]
+
+ epochIndex = filename.find(':')
+ if epochIndex == -1:
+ epoch = ''
+ else:
+ epoch = filename[:epochIndex]
+
+ name = filename[epochIndex + 1:verIndex]
+ return name, ver, rel, epoch, arch
+
+def getCanonX86Arch(arch):
+ #
+ if arch == "i586":
+ f = open("/proc/cpuinfo", "r")
+ lines = f.readlines()
+ f.close()
+ for line in lines:
+ if line.startswith("model name") and line.find("Geode(TM)") != -1:
+ return "geode"
+ return arch
+ # only athlon vs i686 isn't handled with uname currently
+ if arch != "i686":
+ return arch
+
+ # if we're i686 and AuthenticAMD, then we should be an athlon
+ f = open("/proc/cpuinfo", "r")
+ lines = f.readlines()
+ f.close()
+ for line in lines:
+ if line.startswith("vendor") and line.find("AuthenticAMD") != -1:
+ return "athlon"
+ # i686 doesn't guarantee cmov, but we depend on it
+ elif line.startswith("flags") and line.find("cmov") == -1:
+ return "i586"
+
+ return arch
+
+def getCanonX86_64Arch(arch):
+ if arch != "x86_64":
+ return arch
+
+ vendor = None
+ f = open("/proc/cpuinfo", "r")
+ lines = f.readlines()
+ f.close()
+ for line in lines:
+ if line.startswith("vendor_id"):
+ vendor = line.split(':')[1]
+ break
+ if vendor is None:
+ return arch
+
+ if vendor.find("Authentic AMD") != -1 or vendor.find("AuthenticAMD") != -1:
+ return "amd64"
+ if vendor.find("GenuineIntel") != -1:
+ return "ia32e"
+ return arch
+
+def getCanonArch():
+ arch = os.uname()[4]
+
+ if (len(arch) == 4 and arch[0] == "i" and arch[2:4] == "86"):
+ return getCanonX86Arch(arch)
+
+ if arch == "x86_64":
+ return getCanonX86_64Arch(arch)
+
+ return arch
+
+# Copy from libsatsolver:poolarch.c, with cleanup
+archPolicies = {
+ "x86_64": "x86_64:i686:i586:i486:i386",
+ "i686": "i686:i586:i486:i386",
+ "i586": "i586:i486:i386",
+ "ia64": "ia64:i686:i586:i486:i386",
+ "aarch64": "aarch64",
+ "armv7tnhl": "armv7tnhl:armv7thl:armv7nhl:armv7hl",
+ "armv7thl": "armv7thl:armv7hl",
+ "armv7nhl": "armv7nhl:armv7hl",
+ "armv7hl": "armv7hl",
+ "armv7l": "armv7l:armv6l:armv5tejl:armv5tel:armv5l:armv4tl:armv4l:armv3l",
+ "armv6l": "armv6l:armv5tejl:armv5tel:armv5l:armv4tl:armv4l:armv3l",
+ "armv5tejl": "armv5tejl:armv5tel:armv5l:armv4tl:armv4l:armv3l",
+ "armv5tel": "armv5tel:armv5l:armv4tl:armv4l:armv3l",
+ "armv5l": "armv5l:armv4tl:armv4l:armv3l",
+ "mipsel": "mipsel",
+ "riscv64": "riscv64",
+}
+
+# dict mapping arch -> ( multicompat, best personality, biarch personality )
+multilibArches = {
+ "x86_64": ( "athlon", "x86_64", "athlon" ),
+}
+
+# from yumUtils.py
+arches = {
+ # ia32
+ "athlon": "i686",
+ "i686": "i586",
+ "geode": "i586",
+ "i586": "i486",
+ "i486": "i386",
+ "i386": "noarch",
+
+ # amd64
+ "x86_64": "athlon",
+ "amd64": "x86_64",
+ "ia32e": "x86_64",
+
+ # arm
+ "armv7tnhl": "armv7nhl",
+ "armv7nhl": "armv7hl",
+ "armv7hl": "noarch",
+ "armv7l": "armv6l",
+ "armv6l": "armv5tejl",
+ "armv5tejl": "armv5tel",
+ "armv5tel": "noarch",
+
+ #itanium
+ "ia64": "noarch",
+
+ "mipsel": "mipsel",
+
+ "riscv64": "noarch",
+}
+
+def isMultiLibArch(arch=None):
+ """returns true if arch is a multilib arch, false if not"""
+ if arch is None:
+ arch = getCanonArch()
+
+ if not arches.has_key(arch): # or we could check if it is noarch
+ return False
+
+ if multilibArches.has_key(arch):
+ return True
+
+ if multilibArches.has_key(arches[arch]):
+ return True
+
+ return False
+
+def getBaseArch():
+ myarch = getCanonArch()
+ if not arches.has_key(myarch):
+ return myarch
+
+ if isMultiLibArch(arch=myarch):
+ if multilibArches.has_key(myarch):
+ return myarch
+ else:
+ return arches[myarch]
+
+ if arches.has_key(myarch):
+ basearch = myarch
+ value = arches[basearch]
+ while value != 'noarch':
+ basearch = value
+ value = arches[basearch]
+
+ return basearch
+
+def checkRpmIntegrity(bin_rpm, package):
+ return runner.quiet([bin_rpm, "-K", "--nosignature", package])
+
+def checkSig(ts, package):
+ """ Takes a transaction set and a package, check it's sigs,
+ return 0 if they are all fine
+ return 1 if the gpg key can't be found
+ return 2 if the header is in someway damaged
+ return 3 if the key is not trusted
+ return 4 if the pkg is not gpg or pgp signed
+ """
+
+ value = 0
+ currentflags = ts.setVSFlags(0)
+ fdno = os.open(package, os.O_RDONLY)
+ try:
+ hdr = ts.hdrFromFdno(fdno)
+
+ except rpm.error as e:
+ if str(e) == "public key not availaiable":
+ value = 1
+ if str(e) == "public key not available":
+ value = 1
+ if str(e) == "public key not trusted":
+ value = 3
+ if str(e) == "error reading package header":
+ value = 2
+ else:
+ error, siginfo = getSigInfo(hdr)
+ if error == 101:
+ os.close(fdno)
+ del hdr
+ value = 4
+ else:
+ del hdr
+
+ try:
+ os.close(fdno)
+ except OSError:
+ pass
+
+ ts.setVSFlags(currentflags) # put things back like they were before
+ return value
+
+def getSigInfo(hdr):
+ """ checks signature from an hdr hand back signature information and/or
+ an error code
+ """
+
+ import locale
+ locale.setlocale(locale.LC_ALL, 'C')
+
+ string = '%|DSAHEADER?{%{DSAHEADER:pgpsig}}:{%|RSAHEADER?{%{RSAHEADER:pgpsig}}:{%|SIGGPG?{%{SIGGPG:pgpsig}}:{%|SIGPGP?{%{SIGPGP:pgpsig}}:{(none)}|}|}|}|'
+ siginfo = hdr.sprintf(string)
+ if siginfo != '(none)':
+ error = 0
+ sigtype, sigdate, sigid = siginfo.split(',')
+ else:
+ error = 101
+ sigtype = 'MD5'
+ sigdate = 'None'
+ sigid = 'None'
+
+ infotuple = (sigtype, sigdate, sigid)
+ return error, infotuple
+
--- /dev/null
+#!/usr/bin/python -tt
+#
+# Copyright (c) 2011 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+import subprocess
+
+from mic import msger
+from mic.utils import errors
+
+def runtool(cmdln_or_args, catch=1):
+ """ wrapper for most of the subprocess calls
+ input:
+ cmdln_or_args: can be both args and cmdln str (shell=True)
+ catch: 0, quitely run
+ 1, only STDOUT
+ 2, only STDERR
+ 3, both STDOUT and STDERR
+ return:
+ (rc, output)
+ if catch==0: the output will always None
+ """
+
+ if catch not in (0, 1, 2, 3):
+ # invalid catch selection, will cause exception, that's good
+ return None
+
+ if isinstance(cmdln_or_args, list):
+ cmd = cmdln_or_args[0]
+ shell = False
+ else:
+ import shlex
+ cmd = shlex.split(cmdln_or_args)[0]
+ shell = True
+
+ if catch != 3:
+ dev_null = os.open("/dev/null", os.O_WRONLY)
+
+ if catch == 0:
+ sout = dev_null
+ serr = dev_null
+ elif catch == 1:
+ sout = subprocess.PIPE
+ serr = dev_null
+ elif catch == 2:
+ sout = dev_null
+ serr = subprocess.PIPE
+ elif catch == 3:
+ sout = subprocess.PIPE
+ serr = subprocess.STDOUT
+
+ try:
+ p = subprocess.Popen(cmdln_or_args, stdout=sout,
+ stderr=serr, shell=shell)
+ (sout, serr) = p.communicate()
+ # combine stdout and stderr, filter None out
+ out = ''.join(filter(None, [sout, serr]))
+ except OSError as e:
+ if e.errno == 2:
+ # [Errno 2] No such file or directory
+ raise errors.CreatorError('Cannot run command: %s, lost dependency?' % cmd)
+ else:
+ raise # relay
+ finally:
+ if catch != 3:
+ os.close(dev_null)
+
+ return (p.returncode, out)
+
+def show(cmdln_or_args):
+ # show all the message using msger.verbose
+
+ rc, out = runtool(cmdln_or_args, catch=3)
+
+ if isinstance(cmdln_or_args, list):
+ cmd = ' '.join(cmdln_or_args)
+ else:
+ cmd = cmdln_or_args
+
+ msg = 'running command: "%s"' % cmd
+ if out: out = out.strip()
+ if out:
+ msg += ', with output::'
+ msg += '\n +----------------'
+ for line in out.splitlines():
+ msg += '\n | %s' % line
+ msg += '\n +----------------'
+
+ msger.verbose(msg)
+ return rc
+
+def outs(cmdln_or_args, catch=1):
+ # get the outputs of tools
+ return runtool(cmdln_or_args, catch)[1].strip()
+
+def quiet(cmdln_or_args):
+ return runtool(cmdln_or_args, catch=0)[0]
--- /dev/null
+# Copyright (c) 2014 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""
+This module provides a class SafeURL which can contain url/user/password read
+from config file, and hide plain user and password when it print to screen
+"""
+import os.path
+import urllib
+from urlparse import urlsplit, urlunsplit
+
+
+def join_userpass(href, user, passwd):
+ """Return authenticated URL with user and passwd embeded"""
+ if not user and not passwd:
+ return href
+
+ if passwd:
+ userpass = '%s:%s' % (urllib.quote(user, safe=''),
+ urllib.quote(passwd, safe=''))
+ else:
+ userpass = urllib.quote(user, safe='')
+
+ parts = urlsplit(href)
+ netloc = '%s@%s' % (userpass, parts[1])
+ comps = list(parts)
+ comps[1] = netloc
+ return urlunsplit(comps)
+
+
+def split_userpass(href):
+ """Returns (href, user, passwd) of an authenticated URL"""
+ parts = urlsplit(href)
+
+ netloc = parts[1]
+ if '@' not in netloc:
+ return href, None, None
+
+ userpass, netloc = netloc.split('@', 1)
+ if ':' in userpass:
+ user, passwd = [ urllib.unquote(i)
+ for i in userpass.split(':', 1) ]
+ else:
+ user, passwd = userpass, None
+
+ comps = list(parts)
+ comps[1] = netloc
+ return urlunsplit(comps), user, passwd
+
+
+class SafeURL(str):
+ '''SafeURL can hide user info when it's printed to console.
+ Use property full to get url with user info
+ '''
+ def __new__(cls, urlstring, user=None, passwd=None):
+ """Imuutable object"""
+ href, user1, passwd1 = split_userpass(urlstring)
+ user = user if user else user1
+ passwd = passwd if passwd else passwd1
+
+ obj = super(SafeURL, cls).__new__(cls, href)
+ obj.user = user
+ obj.passwd = passwd
+ obj.full = join_userpass(href, user, passwd)
+
+ parts = urlsplit(href)
+ obj.scheme = parts[0]
+ obj.netloc = parts[1]
+ obj.path = parts[2]
+ obj.host = parts.hostname
+ obj.port = parts.port
+ return obj
+
+ def join(self, *path):
+ """Returns a new SafeURL with new path. Search part is removed since
+ after join path is changed, keep the same search part is useless.
+ """
+ idx = self.full.find('?')
+ url = self.full if idx < 0 else self.full[:idx]
+ return SafeURL(os.path.join(url.rstrip('/'), *path))
install -d -m0755 %{buildroot}/%{_sysconfdir}/zsh_completion.d/
install -Dp -m0755 etc/zsh_completion.d/_%{name} %{buildroot}/%{_sysconfdir}/zsh_completion.d/
+#install mic py2 code.
+mkdir -p %{buildroot}/%{_prefix}/lib/%{name}/mic_py2
+cp -rp mic_py2/* %{buildroot}%{_prefix}/lib/%{name}/mic_py2
+
%files
%defattr(-,root,root,-)
%doc doc/*
%{_bindir}/mic
%{_sysconfdir}/bash_completion.d
%{_sysconfdir}/zsh_completion.d
-