Switch lorax to use dnf instead of yum
pylorax users will need to change to using dnf and pass a dnf.Base() object as the dbo argument instead of a yum object as the yum or ybo argument. See the lorax script for an example of how to do this. The lorax cmdline argument --excludepkgs has been removed since dnf doesn't appear to have any way to support it and packages should be controlled using templates anyway.
This commit is contained in:
parent
4b55e1eb7a
commit
431ca6cea4
@ -37,9 +37,9 @@ Requires: squashfs-tools >= 4.2
|
||||
Requires: util-linux
|
||||
Requires: xz
|
||||
Requires: pigz
|
||||
Requires: yum
|
||||
Requires: pykickstart
|
||||
Requires: dracut >= 030
|
||||
Requires: dnf
|
||||
|
||||
%if 0%{?fedora}
|
||||
# Fedora specific deps
|
||||
|
@ -36,7 +36,7 @@ import selinux
|
||||
from pylorax.base import BaseLoraxClass, DataHolder
|
||||
import pylorax.output as output
|
||||
|
||||
import yum
|
||||
import dnf
|
||||
|
||||
from pylorax.sysutils import joinpaths, remove, linktree
|
||||
from rpmUtils.arch import getBaseArch
|
||||
@ -96,9 +96,6 @@ class Lorax(BaseLoraxClass):
|
||||
self.conf.add_section("templates")
|
||||
self.conf.set("templates", "ramdisk", "ramdisk.ltmpl")
|
||||
|
||||
self.conf.add_section("yum")
|
||||
self.conf.set("yum", "skipbroken", "0")
|
||||
|
||||
self.conf.add_section("compression")
|
||||
self.conf.set("compression", "type", "xz")
|
||||
self.conf.set("compression", "args", "")
|
||||
@ -149,7 +146,7 @@ class Lorax(BaseLoraxClass):
|
||||
fh.setLevel(logging.DEBUG)
|
||||
logger.addHandler(fh)
|
||||
|
||||
def run(self, ybo, product, version, release, variant="", bugurl="",
|
||||
def run(self, dbo, product, version, release, variant="", bugurl="",
|
||||
isfinal=False, workdir=None, outputdir=None, buildarch=None, volid=None,
|
||||
domacboot=True, doupgrade=True, remove_temp=False,
|
||||
installpkgs=None,
|
||||
@ -221,16 +218,16 @@ class Lorax(BaseLoraxClass):
|
||||
logger.critical("selinux must be disabled or in Permissive mode")
|
||||
sys.exit(1)
|
||||
|
||||
# do we have a proper yum base object?
|
||||
logger.info("checking yum base object")
|
||||
if not isinstance(ybo, yum.YumBase):
|
||||
logger.critical("no yum base object")
|
||||
# do we have a proper dnf base object?
|
||||
logger.info("checking dnf base object")
|
||||
if not isinstance(dbo, dnf.Base):
|
||||
logger.critical("no dnf base object")
|
||||
sys.exit(1)
|
||||
self.inroot = ybo.conf.installroot
|
||||
self.inroot = dbo.conf.installroot
|
||||
logger.debug("using install root: {0}".format(self.inroot))
|
||||
|
||||
if not buildarch:
|
||||
buildarch = get_buildarch(ybo)
|
||||
buildarch = get_buildarch(dbo)
|
||||
|
||||
logger.info("setting up build architecture")
|
||||
self.arch = ArchData(buildarch)
|
||||
@ -253,15 +250,14 @@ class Lorax(BaseLoraxClass):
|
||||
sys.exit(1)
|
||||
|
||||
templatedir = self.conf.get("lorax", "sharedir")
|
||||
# NOTE: rb.root = ybo.conf.installroot (== self.inroot)
|
||||
# NOTE: rb.root = dbo.conf.installroot (== self.inroot)
|
||||
rb = RuntimeBuilder(product=self.product, arch=self.arch,
|
||||
yum=ybo, templatedir=templatedir,
|
||||
dbo=dbo, templatedir=templatedir,
|
||||
installpkgs=installpkgs,
|
||||
add_templates=add_templates,
|
||||
add_template_vars=add_template_vars)
|
||||
|
||||
logger.info("installing runtime packages")
|
||||
rb.yum.conf.skip_broken = self.conf.getboolean("yum", "skipbroken")
|
||||
rb.install()
|
||||
|
||||
# write .buildstamp
|
||||
@ -358,10 +354,12 @@ class Lorax(BaseLoraxClass):
|
||||
remove(self.workdir)
|
||||
|
||||
|
||||
def get_buildarch(ybo):
|
||||
def get_buildarch(dbo):
|
||||
# get architecture of the available anaconda package
|
||||
buildarch = None
|
||||
for anaconda in ybo.doPackageLists(patterns=["anaconda"]).available:
|
||||
q = dbo.sack.query()
|
||||
a = q.available()
|
||||
for anaconda in a.filter(name="anaconda"):
|
||||
if anaconda.arch != "src":
|
||||
buildarch = anaconda.arch
|
||||
break
|
||||
|
107
src/pylorax/dnfhelper.py
Normal file
107
src/pylorax/dnfhelper.py
Normal file
@ -0,0 +1,107 @@
|
||||
#
|
||||
# dnfhelper.py
|
||||
#
|
||||
# Copyright (C) 2010-2014 Red Hat, 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
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# 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, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Red Hat Author(s): Martin Gracik <mgracik@redhat.com>
|
||||
# Brian C. Lane <bcl@redhat.com>
|
||||
#
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger("pylorax.dnfhelper")
|
||||
import dnf
|
||||
import collections
|
||||
import time
|
||||
import pylorax.output as output
|
||||
|
||||
__all__ = ['LoraxDownloadCallback', 'LoraxRpmCallback']
|
||||
|
||||
def _paced(fn):
|
||||
"""Execute `fn` no more often then every 2 seconds."""
|
||||
def paced_fn(self, *args):
|
||||
now = time.time()
|
||||
if now - self.last_time < 2:
|
||||
return
|
||||
self.last_time = now
|
||||
return fn(self, *args)
|
||||
return paced_fn
|
||||
|
||||
|
||||
class LoraxDownloadCallback(dnf.callback.DownloadProgress):
|
||||
def __init__(self):
|
||||
self.downloads = collections.defaultdict(int)
|
||||
self.last_time = time.time()
|
||||
self.total_files = 0
|
||||
self.total_size = 0
|
||||
|
||||
self.pkgno = 0
|
||||
self.total = 0
|
||||
|
||||
self.output = output.LoraxOutput()
|
||||
|
||||
@_paced
|
||||
def _update(self):
|
||||
msg = "Downloading %(pkgno)s / %(total_files)s RPMs, " \
|
||||
"%(downloaded)s / %(total_size)s (%(percent)d%%) done.\n"
|
||||
downloaded = sum(self.downloads.values())
|
||||
vals = {
|
||||
'downloaded' : downloaded,
|
||||
'percent' : int(100 * downloaded/self.total_size),
|
||||
'pkgno' : self.pkgno,
|
||||
'total_files' : self.total_files,
|
||||
'total_size' : self.total_size
|
||||
}
|
||||
self.output.write(msg % vals)
|
||||
|
||||
def end(self, payload, status, err_msg):
|
||||
nevra = str(payload)
|
||||
if status is dnf.callback.STATUS_OK:
|
||||
self.downloads[nevra] = payload.download_size
|
||||
self.pkgno += 1
|
||||
self._update()
|
||||
return
|
||||
logger.critical("Failed to download '%s': %d - %s", nevra, status, err_msg)
|
||||
|
||||
def progress(self, payload, done):
|
||||
nevra = str(payload)
|
||||
self.downloads[nevra] = done
|
||||
self._update()
|
||||
|
||||
def start(self, total_files, total_size):
|
||||
self.total_files = total_files
|
||||
self.total_size = total_size
|
||||
|
||||
|
||||
class LoraxRpmCallback(dnf.callback.LoggingTransactionDisplay):
|
||||
def __init__(self, queue):
|
||||
super(LoraxRpmCallback, self).__init__()
|
||||
self._queue = queue
|
||||
self._last_ts = None
|
||||
self.cnt = 0
|
||||
|
||||
def event(self, package, action, te_current, te_total, ts_current, ts_total):
|
||||
if action == self.PKG_INSTALL and te_current == 0:
|
||||
# do not report same package twice
|
||||
if self._last_ts == ts_current:
|
||||
return
|
||||
self._last_ts = ts_current
|
||||
|
||||
msg = '(%d/%d) %s.%s' % \
|
||||
(ts_current, ts_total, package.name, package.arch)
|
||||
self.cnt += 1
|
||||
self._queue.put(('install', msg))
|
||||
elif action == self.TRANS_POST:
|
||||
self._queue.put(('post', None))
|
@ -28,15 +28,18 @@ from os.path import basename, isdir
|
||||
from subprocess import CalledProcessError
|
||||
|
||||
from pylorax.sysutils import joinpaths, cpfile, mvfile, replace, remove
|
||||
from pylorax.yumhelper import LoraxDownloadCallback, LoraxTransactionCallback, LoraxRpmCallback
|
||||
from pylorax.dnfhelper import LoraxDownloadCallback, LoraxRpmCallback
|
||||
from pylorax.base import DataHolder
|
||||
from pylorax.executils import runcmd, runcmd_output
|
||||
from pylorax.imgutils import mkcpio
|
||||
import pylorax.output as output
|
||||
|
||||
from mako.lookup import TemplateLookup
|
||||
from mako.exceptions import text_error_template
|
||||
import sys, traceback
|
||||
import struct
|
||||
import dnf
|
||||
import multiprocessing
|
||||
|
||||
class LoraxTemplate(object):
|
||||
def __init__(self, directories=None):
|
||||
@ -108,7 +111,7 @@ class LoraxTemplateRunner(object):
|
||||
This class parses and executes Lorax templates. Sample usage:
|
||||
|
||||
# install a bunch of packages
|
||||
runner = LoraxTemplateRunner(inroot=rundir, outroot=rundir, yum=yum_obj)
|
||||
runner = LoraxTemplateRunner(inroot=rundir, outroot=rundir, dbo=dnf_obj)
|
||||
runner.run("install-packages.ltmpl")
|
||||
|
||||
# modify a runtime dir
|
||||
@ -145,11 +148,11 @@ class LoraxTemplateRunner(object):
|
||||
|
||||
* Commands should raise exceptions for errors - don't use sys.exit()
|
||||
'''
|
||||
def __init__(self, inroot, outroot, yum=None, fatalerrors=True,
|
||||
def __init__(self, inroot, outroot, dbo=None, fatalerrors=True,
|
||||
templatedir=None, defaults=None):
|
||||
self.inroot = inroot
|
||||
self.outroot = outroot
|
||||
self.yum = yum
|
||||
self.dbo = dbo
|
||||
self.fatalerrors = fatalerrors
|
||||
self.templatedir = templatedir or "/usr/share/lorax"
|
||||
self.templatefile = None
|
||||
@ -166,8 +169,8 @@ class LoraxTemplateRunner(object):
|
||||
return joinpaths(self.inroot, path)
|
||||
|
||||
def _filelist(self, *pkgs):
|
||||
pkglist = self.yum.doPackageLists(pkgnarrow="installed", patterns=pkgs)
|
||||
return set([f for pkg in pkglist.installed for f in pkg.filelist+pkg.ghostlist])
|
||||
pkglist = self.dbo.doPackageLists(pkgnarrow="installed", patterns=pkgs)
|
||||
return set([f for pkg in pkglist for f in pkg.files])
|
||||
|
||||
def _getsize(self, *files):
|
||||
return sum(os.path.getsize(self._out(f)) for f in files if os.path.isfile(self._out(f)))
|
||||
@ -447,9 +450,9 @@ class LoraxTemplateRunner(object):
|
||||
cmd = cmd[1:]
|
||||
|
||||
try:
|
||||
output = runcmd_output(cmd, cwd=cwd)
|
||||
if output:
|
||||
logger.debug('command output:\n%s', output)
|
||||
stdout = runcmd_output(cmd, cwd=cwd)
|
||||
if stdout:
|
||||
logger.debug('command output:\n%s', stdout)
|
||||
logger.debug("command finished successfully")
|
||||
except CalledProcessError as e:
|
||||
if e.output:
|
||||
@ -471,7 +474,7 @@ class LoraxTemplateRunner(object):
|
||||
|
||||
for p in pkgs:
|
||||
try:
|
||||
self.yum.install(pattern=p)
|
||||
self.dbo.install(p)
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
# FIXME: save exception and re-raise after the loop finishes
|
||||
logger.error("installpkg %s failed: %s", p, str(e))
|
||||
@ -501,19 +504,60 @@ class LoraxTemplateRunner(object):
|
||||
Actually install all the packages requested by previous 'installpkg'
|
||||
commands.
|
||||
'''
|
||||
self.yum.buildTransaction()
|
||||
dl_callback = LoraxDownloadCallback()
|
||||
self.yum.repos.setProgressBar(dl_callback)
|
||||
self.yum.processTransaction(callback=LoraxTransactionCallback(dl_callback),
|
||||
rpmDisplay=LoraxRpmCallback())
|
||||
|
||||
def do_transaction(base, queue):
|
||||
try:
|
||||
display = LoraxRpmCallback(queue)
|
||||
base.do_transaction(display=display)
|
||||
except BaseException as e:
|
||||
logger.error("The transaction process has ended abruptly: %s", e)
|
||||
queue.put(('quit', str(e)))
|
||||
|
||||
self.dbo.reset()
|
||||
try:
|
||||
logger.info("Checking dependencies")
|
||||
self.dbo.resolve()
|
||||
except dnf.exceptions.DepsolveError as e:
|
||||
logger.error("Dependency check failed: %s", e)
|
||||
raise
|
||||
logger.info("%d packages selected", len(self.dbo.transaction))
|
||||
if len(self.dbo.transaction) == 0:
|
||||
raise Exception("No packages in transaction")
|
||||
|
||||
pkgs_to_download = self.dbo.transaction.install_set
|
||||
logger.info("Downloading packages")
|
||||
progress = LoraxDownloadCallback()
|
||||
try:
|
||||
self.dbo.download_packages(pkgs_to_download, progress)
|
||||
except dnf.exceptions.DownloadError as e:
|
||||
logger.error("Failed to download the following packages: %s", e)
|
||||
raise
|
||||
|
||||
logger.info("Preparing transaction from installation source")
|
||||
queue = multiprocessing.Queue()
|
||||
msgout = output.LoraxOutput()
|
||||
process = multiprocessing.Process(target=do_transaction, args=(self.dbo, queue))
|
||||
process.start()
|
||||
(token, msg) = queue.get()
|
||||
while token not in ('post', 'quit'):
|
||||
if token == 'install':
|
||||
logging.info("%s", msg)
|
||||
msgout.writeline(msg)
|
||||
(token, msg) = queue.get()
|
||||
if token == 'quit':
|
||||
logger.error("Transaction failed.")
|
||||
raise Exception("Transaction failed")
|
||||
|
||||
logger.info("Performing post-installation setup tasks")
|
||||
process.join()
|
||||
|
||||
# verify if all packages that were supposed to be installed,
|
||||
# are really installed
|
||||
errs = [t.po for t in self.yum.tsInfo if not self.yum.rpmdb.contains(po=t.po)]
|
||||
errs = [t.po for t in self.dbo.tsInfo if not self.dbo.rpmdb.contains(po=t.po)]
|
||||
for po in errs:
|
||||
logger.error("package '%s' was not installed", po)
|
||||
|
||||
self.yum.closeRpmDB()
|
||||
self.dbo.close()
|
||||
|
||||
def removefrom(self, pkg, *globs):
|
||||
'''
|
||||
|
@ -67,19 +67,19 @@ def generate_module_info(moddir, outfile=None):
|
||||
|
||||
class RuntimeBuilder(object):
|
||||
'''Builds the anaconda runtime image.'''
|
||||
def __init__(self, product, arch, yum, templatedir=None,
|
||||
def __init__(self, product, arch, dbo, templatedir=None,
|
||||
installpkgs=None,
|
||||
add_templates=None,
|
||||
add_template_vars=None):
|
||||
root = yum.conf.installroot
|
||||
root = dbo.conf.installroot
|
||||
# use a copy of product so we can modify it locally
|
||||
product = product.copy()
|
||||
product.name = product.name.lower()
|
||||
self.vars = DataHolder(arch=arch, product=product, yum=yum, root=root,
|
||||
self.vars = DataHolder(arch=arch, product=product, dbo=dbo, root=root,
|
||||
basearch=arch.basearch, libdir=arch.libdir)
|
||||
self.yum = yum
|
||||
self.dbo = dbo
|
||||
self._runner = LoraxTemplateRunner(inroot=root, outroot=root,
|
||||
yum=yum, templatedir=templatedir)
|
||||
dbo=dbo, templatedir=templatedir)
|
||||
self.add_templates = add_templates or []
|
||||
self.add_template_vars = add_template_vars or {}
|
||||
self._installpkgs = installpkgs or []
|
||||
@ -87,7 +87,9 @@ class RuntimeBuilder(object):
|
||||
|
||||
def _install_branding(self):
|
||||
release = None
|
||||
for pkg in self.yum.whatProvides('/etc/system-release', None, None):
|
||||
q = self.dbo.sack.query()
|
||||
a = q.available()
|
||||
for pkg in a.filter(provides='/etc/system-release'):
|
||||
if pkg.name.startswith('generic'):
|
||||
continue
|
||||
else:
|
||||
@ -119,9 +121,10 @@ class RuntimeBuilder(object):
|
||||
'''debugging data: write out lists of package contents'''
|
||||
if not os.path.isdir(pkglistdir):
|
||||
os.makedirs(pkglistdir)
|
||||
for pkgobj in self.yum.doPackageLists(pkgnarrow='installed').installed:
|
||||
q = self.dbo.sack.query()
|
||||
for pkgobj in q.installed():
|
||||
with open(joinpaths(pkglistdir, pkgobj.name), "w") as fobj:
|
||||
for fname in pkgobj.filelist + pkgobj.dirlist:
|
||||
for fname in pkgobj.files:
|
||||
fobj.write("{0}\n".format(fname))
|
||||
|
||||
def postinstall(self):
|
||||
@ -143,8 +146,9 @@ class RuntimeBuilder(object):
|
||||
'''debugging data: write a big list of pkg sizes'''
|
||||
fobj = open(pkgsizefile, "w")
|
||||
getsize = lambda f: os.lstat(f).st_size if os.path.exists(f) else 0
|
||||
for p in sorted(self.yum.doPackageLists(pkgnarrow='installed').installed):
|
||||
pkgsize = sum(getsize(joinpaths(self.vars.root,f)) for f in p.filelist)
|
||||
q = self.dbo.sack.query()
|
||||
for p in sorted(q.installed()):
|
||||
pkgsize = sum(getsize(joinpaths(self.vars.root,f)) for f in p.files)
|
||||
fobj.write("{0.name}.{0.arch}: {1}\n".format(p, pkgsize))
|
||||
|
||||
def generate_module_data(self):
|
||||
|
@ -1,127 +0,0 @@
|
||||
#
|
||||
# yumhelper.py
|
||||
#
|
||||
# Copyright (C) 2010-2014 Red Hat, 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
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# 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, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Red Hat Author(s): Martin Gracik <mgracik@redhat.com>
|
||||
#
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger("pylorax.yumhelper")
|
||||
import sys
|
||||
import yum, yum.callbacks, yum.rpmtrans
|
||||
import pylorax.output as output
|
||||
|
||||
__all__ = ['LoraxDownloadCallback', 'LoraxTransactionCallback',
|
||||
'LoraxRpmCallback']
|
||||
|
||||
class LoraxDownloadCallback(yum.callbacks.DownloadBaseCallback):
|
||||
def __init__(self):
|
||||
yum.callbacks.DownloadBaseCallback.__init__(self)
|
||||
|
||||
self.pkgno = 0
|
||||
self.total = 0
|
||||
|
||||
self.output = output.LoraxOutput()
|
||||
|
||||
|
||||
def updateProgress(self, name, frac, fread, ftime):
|
||||
"""
|
||||
Update the progress bar
|
||||
@param name: filename
|
||||
@param frac: progress fraction (0 -> 1)
|
||||
@param fread: formated string containing BytesRead
|
||||
@param ftime: formated string containing remaining or elapsed time
|
||||
"""
|
||||
# Only update when it is finished downloading
|
||||
if frac < 1:
|
||||
return
|
||||
|
||||
self.pkgno += 1
|
||||
info = "({0:3d}/{1:3d}) "
|
||||
info = info.format(self.pkgno, self.total)
|
||||
|
||||
infolen, pkglen = len(info), len(name)
|
||||
if (infolen + pkglen) > self.output.width:
|
||||
name = "{0}...".format(name[:self.output.width-infolen-3])
|
||||
|
||||
msg = "{0}<b>{1}</b>\n".format(info, name)
|
||||
self.output.write(msg)
|
||||
|
||||
|
||||
class LoraxTransactionCallback(object):
|
||||
|
||||
def __init__(self, dl_callback):
|
||||
self.output = output.LoraxOutput()
|
||||
|
||||
self.dl_callback = dl_callback
|
||||
|
||||
def event(self, state, data=None):
|
||||
if state == yum.callbacks.PT_DOWNLOAD:
|
||||
self.output.write("downloading packages\n")
|
||||
elif state == yum.callbacks.PT_DOWNLOAD_PKGS:
|
||||
# Initialize the total number of packages being downloaded
|
||||
self.dl_callback.total = len(data)
|
||||
elif state == yum.callbacks.PT_GPGCHECK:
|
||||
self.output.write("checking package signatures\n")
|
||||
elif state == yum.callbacks.PT_TEST_TRANS:
|
||||
self.output.write("running test transaction\n")
|
||||
elif state == yum.callbacks.PT_TRANSACTION:
|
||||
self.output.write("running transaction\n")
|
||||
|
||||
|
||||
class LoraxRpmCallback(yum.rpmtrans.RPMBaseCallback):
|
||||
|
||||
def __init__(self):
|
||||
yum.rpmtrans.RPMBaseCallback.__init__(self)
|
||||
self.output = output.LoraxOutput()
|
||||
|
||||
def event(self, package, action, te_current, te_total,
|
||||
ts_current, ts_total):
|
||||
|
||||
action_str = self.action[action].encode("utf-8")
|
||||
info = "({0:3d}/{1:3d}) [{2:3.0f}%] {3} "
|
||||
info = info.format(ts_current, ts_total,
|
||||
float(te_current) / float(te_total) * 100,
|
||||
action_str.lower())
|
||||
|
||||
pkg = "{0}".format(package)
|
||||
|
||||
infolen, pkglen = len(info), len(pkg)
|
||||
if (infolen + pkglen) > self.output.width:
|
||||
pkg = "{0}...".format(pkg[:self.output.width-infolen-3])
|
||||
|
||||
msg = "{0}<b>{1}</b>".format(info, pkg)
|
||||
|
||||
# When not outputting to a tty we only want to print it once at the end
|
||||
if sys.stdout.isatty():
|
||||
self.output.write(msg + "\r")
|
||||
if te_current == te_total:
|
||||
self.output.write("\n")
|
||||
elif te_current == te_total:
|
||||
self.output.write(msg + "\n")
|
||||
|
||||
|
||||
def filelog(self, package, action):
|
||||
if self.fileaction.get(action) == "Installed":
|
||||
logger.debug("{0} installed successfully".format(package))
|
||||
|
||||
def errorlog(self, msg):
|
||||
logger.warning("RPM transaction error: %s", msg)
|
||||
|
||||
def scriptout(self, package, msgs):
|
||||
if msgs:
|
||||
logger.info("%s scriptlet output:\n%s", package, msgs)
|
161
src/sbin/lorax
161
src/sbin/lorax
@ -25,20 +25,16 @@ import logging
|
||||
log = logging.getLogger("lorax")
|
||||
program_log = logging.getLogger("program")
|
||||
pylorax_log = logging.getLogger("pylorax")
|
||||
yum_log = logging.getLogger("yum")
|
||||
dnf_log = logging.getLogger("dnf")
|
||||
|
||||
|
||||
import sys
|
||||
import os
|
||||
import tempfile
|
||||
from optparse import OptionParser, OptionGroup
|
||||
import ConfigParser
|
||||
import shutil
|
||||
|
||||
import yum
|
||||
# This is a bit of a hack to short circuit yum's internal logging
|
||||
# handler setup. We already set one up so we don't need it to run.
|
||||
yum.logginglevels._added_handlers = True
|
||||
import dnf
|
||||
import pylorax
|
||||
|
||||
def setup_logging(opts):
|
||||
@ -67,12 +63,12 @@ def setup_logging(opts):
|
||||
fh.setLevel(logging.DEBUG)
|
||||
program_log.addHandler(fh)
|
||||
|
||||
# yum logging
|
||||
yum_log.setLevel(logging.DEBUG)
|
||||
logfile = os.path.abspath(os.path.dirname(opts.logfile))+"/yum.log"
|
||||
# dnf logging
|
||||
dnf_log.setLevel(logging.DEBUG)
|
||||
logfile = os.path.abspath(os.path.dirname(opts.logfile))+"/dnf.log"
|
||||
fh = logging.FileHandler(filename=logfile, mode="w")
|
||||
fh.setLevel(logging.DEBUG)
|
||||
yum_log.addHandler(fh)
|
||||
dnf_log.addHandler(fh)
|
||||
|
||||
|
||||
def main(args):
|
||||
@ -116,9 +112,6 @@ def main(args):
|
||||
help="config file", metavar="STRING")
|
||||
optional.add_option("--proxy", default=None,
|
||||
help="repo proxy url:port", metavar="STRING")
|
||||
optional.add_option("-e", "--excludepkgs", default=[],
|
||||
action="append", metavar="STRING",
|
||||
help="package glob to exclude (may be listed multiple times)")
|
||||
optional.add_option("-i", "--installpkgs", default=[],
|
||||
action="append", metavar="STRING",
|
||||
help="package glob to install before runtime-install.tmpl runs. (may be listed multiple times)")
|
||||
@ -180,17 +173,16 @@ def main(args):
|
||||
# create the temporary directory for lorax
|
||||
tempdir = tempfile.mkdtemp(prefix="lorax.", dir=tempfile.gettempdir())
|
||||
|
||||
# create the yumbase object
|
||||
installtree = os.path.join(tempdir, "installtree")
|
||||
os.mkdir(installtree)
|
||||
yumtempdir = os.path.join(tempdir, "yum")
|
||||
os.mkdir(yumtempdir)
|
||||
dnftempdir = os.path.join(tempdir, "dnf")
|
||||
os.mkdir(dnftempdir)
|
||||
|
||||
yb = get_yum_base_object(installtree, opts.source, opts.mirrorlist,
|
||||
yumtempdir, opts.proxy, opts.excludepkgs)
|
||||
dnfbase = get_dnf_base_object(installtree, opts.source, opts.mirrorlist,
|
||||
dnftempdir, opts.proxy, opts.version)
|
||||
|
||||
if yb is None:
|
||||
print("error: unable to create the yumbase object", file=sys.stderr)
|
||||
if dnfbase is None:
|
||||
print("error: unable to create the dnf base object", file=sys.stderr)
|
||||
shutil.rmtree(tempdir)
|
||||
sys.exit(1)
|
||||
|
||||
@ -204,7 +196,7 @@ def main(args):
|
||||
# run lorax
|
||||
lorax = pylorax.Lorax()
|
||||
lorax.configure(conf_file=opts.config)
|
||||
lorax.run(yb, opts.product, opts.version, opts.release,
|
||||
lorax.run(dnfbase, opts.product, opts.version, opts.release,
|
||||
opts.variant, opts.bugurl, opts.isfinal,
|
||||
workdir=tempdir, outputdir=outputdir, buildarch=opts.buildarch,
|
||||
volid=opts.volid, domacboot=opts.domacboot, doupgrade=opts.doupgrade,
|
||||
@ -214,9 +206,17 @@ def main(args):
|
||||
remove_temp=True)
|
||||
|
||||
|
||||
def get_yum_base_object(installroot, repositories, mirrorlists=None,
|
||||
tempdir="/var/tmp", proxy=None, excludepkgs=None):
|
||||
def get_dnf_base_object(installroot, repositories, mirrorlists=None,
|
||||
tempdir="/var/tmp", proxy=None, releasever="21"):
|
||||
""" Create a dnf Base object and setup the repositories and installroot
|
||||
|
||||
:param string installroot: Full path to the installroot
|
||||
:param list repositories: List of repositories to use for the installation
|
||||
:param list mirrorlist: List of mirrors to use
|
||||
:param string tempdir: Path of temporary directory
|
||||
:param string proxy: http proxy to use when fetching packages
|
||||
:param string releasever: Release version to pass to dnf
|
||||
"""
|
||||
def sanitize_repo(repo):
|
||||
"""Convert bare paths to file:/// URIs, and silently reject protocols unhandled by yum"""
|
||||
if repo.startswith("/"):
|
||||
@ -227,7 +227,6 @@ def get_yum_base_object(installroot, repositories, mirrorlists=None,
|
||||
return None
|
||||
|
||||
mirrorlists = mirrorlists or []
|
||||
excludepkgs = excludepkgs or []
|
||||
|
||||
# sanitize the repositories
|
||||
repositories = map(sanitize_repo, repositories)
|
||||
@ -237,78 +236,70 @@ def get_yum_base_object(installroot, repositories, mirrorlists=None,
|
||||
repositories = filter(bool, repositories)
|
||||
mirrorlists = filter(bool, mirrorlists)
|
||||
|
||||
cachedir = os.path.join(tempdir, "yum.cache")
|
||||
cachedir = os.path.join(tempdir, "dnf.cache")
|
||||
if not os.path.isdir(cachedir):
|
||||
os.mkdir(cachedir)
|
||||
|
||||
yumconf = os.path.join(tempdir, "yum.conf")
|
||||
c = ConfigParser.ConfigParser()
|
||||
logdir = os.path.join(tempdir, "dnf.logs")
|
||||
if not os.path.isdir(logdir):
|
||||
os.mkdir(logdir)
|
||||
|
||||
# add the main section
|
||||
section = "main"
|
||||
data = {"cachedir": cachedir,
|
||||
"keepcache": 0,
|
||||
"gpgcheck": 0,
|
||||
"plugins": 0,
|
||||
"reposdir": "",
|
||||
"tsflags": "nodocs"}
|
||||
dnfbase = dnf.Base()
|
||||
conf = dnfbase.conf
|
||||
conf.logdir = logdir
|
||||
conf.cachedir = cachedir
|
||||
|
||||
# Turn off logging to the console
|
||||
conf.debuglevel = 0
|
||||
conf.errorlevel = 0
|
||||
dnfbase.logging.setup_from_dnf_conf(conf)
|
||||
|
||||
conf.releasever = releasever
|
||||
conf.installroot = installroot
|
||||
conf.prepend_installroot('persistdir')
|
||||
conf.tsflags.append('nodocs')
|
||||
|
||||
if proxy:
|
||||
data["proxy"] = proxy
|
||||
conf.proxy = proxy
|
||||
|
||||
if excludepkgs:
|
||||
data["exclude"] = " ".join(excludepkgs)
|
||||
|
||||
c.add_section(section)
|
||||
map(lambda (key, value): c.set(section, key, value), data.items())
|
||||
|
||||
# add the main repository - the first repository from list
|
||||
section = "lorax-repo"
|
||||
data = {"name": "lorax repo",
|
||||
"baseurl": repositories[0],
|
||||
"enabled": 1}
|
||||
|
||||
c.add_section(section)
|
||||
map(lambda (key, value): c.set(section, key, value), data.items())
|
||||
|
||||
# add the extra repositories
|
||||
for n, extra in enumerate(repositories[1:], start=1):
|
||||
section = "lorax-extra-repo-{0:d}".format(n)
|
||||
data = {"name": "lorax extra repo {0:d}".format(n),
|
||||
"baseurl": extra,
|
||||
"enabled": 1}
|
||||
|
||||
c.add_section(section)
|
||||
map(lambda (key, value): c.set(section, key, value), data.items())
|
||||
# add the repositories
|
||||
for i, r in enumerate(repositories):
|
||||
repo_name = "lorax-repo-%d" % i
|
||||
repo = dnf.repo.Repo(repo_name, cachedir)
|
||||
repo.baseurl = [r]
|
||||
if proxy:
|
||||
repo.proxy = proxy
|
||||
repo.enable()
|
||||
dnfbase.repos.add(repo)
|
||||
log.info("Added '%s': %s", repo_name, r)
|
||||
log.info("Fetching metadata...")
|
||||
try:
|
||||
repo.load()
|
||||
except dnf.exceptions.RepoError as e:
|
||||
log.error("Error fetching metadata for %s: %s", repo_name, e)
|
||||
return None
|
||||
|
||||
# add the mirrorlists
|
||||
for n, mirror in enumerate(mirrorlists, start=1):
|
||||
section = "lorax-mirrorlist-{0:d}".format(n)
|
||||
data = {"name": "lorax mirrorlist {0:d}".format(n),
|
||||
"mirrorlist": mirror,
|
||||
"enabled": 1 }
|
||||
for i, r in enumerate(mirrorlists):
|
||||
repo_name = "lorax-mirrorlist-%d" % i
|
||||
repo = dnf.repo.Repo(repo_name, cachedir)
|
||||
repo.mirrorlist = r
|
||||
if proxy:
|
||||
repo.proxy = proxy
|
||||
repo.enable()
|
||||
dnfbase.repos.add(repo)
|
||||
log.info("Added '%s': %s", repo_name, r)
|
||||
log.info("Fetching metadata...")
|
||||
try:
|
||||
repo.load()
|
||||
except dnf.exceptions.RepoError as e:
|
||||
log.error("Error fetching metadata for %s: %s", repo_name, e)
|
||||
return None
|
||||
|
||||
c.add_section(section)
|
||||
map(lambda (key, value): c.set(section, key, value), data.items())
|
||||
dnfbase.fill_sack(load_system_repo=False)
|
||||
dnfbase.read_comps()
|
||||
|
||||
# write the yum configuration file
|
||||
with open(yumconf, "w") as f:
|
||||
c.write(f)
|
||||
|
||||
# create the yum base object
|
||||
yb = yum.YumBase()
|
||||
|
||||
yb.preconf.fn = yumconf
|
||||
yb.preconf.root = installroot
|
||||
#yb.repos.setCacheDir(cachedir)
|
||||
|
||||
# Turn on as much yum logging as we can
|
||||
yb.preconf.debuglevel = 6
|
||||
yb.preconf.errorlevel = 6
|
||||
yb.logger.setLevel(logging.DEBUG)
|
||||
yb.verbose_logger.setLevel(logging.DEBUG)
|
||||
|
||||
return yb
|
||||
return dnfbase
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
Loading…
Reference in New Issue
Block a user