summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael E Brown <mebrown@michaels-house.net>2007-12-08 23:57:09 -0600
committerMichael E Brown <mebrown@michaels-house.net>2007-12-08 23:57:09 -0600
commita850a68d3efba05e7d48adc94495b7e06dc2a8d2 (patch)
tree043f099c2169beab96c464d47115928e8c567af2
parentdd4c422a56608a17488c309127a2b4706b946ec3 (diff)
downloadmock-a850a68d3efba05e7d48adc94495b7e06dc2a8d2.tar.gz
mock-a850a68d3efba05e7d48adc94495b7e06dc2a8d2.tar.xz
mock-a850a68d3efba05e7d48adc94495b7e06dc2a8d2.zip
backport all 0.9 changes except consolehelper changes.
-rw-r--r--docs/mock.12
-rw-r--r--etc/mock/logging.ini2
-rwxr-xr-xpy/mock.py60
-rw-r--r--py/mock/backend.py83
-rw-r--r--py/mock/plugins/bind_mount.py11
-rw-r--r--py/mock/plugins/ccache.py14
-rw-r--r--py/mock/plugins/root_cache.py18
-rw-r--r--py/mock/plugins/yum_cache.py14
-rwxr-xr-xpy/mock/trace_decorator.py72
-rw-r--r--py/mock/uid.py22
-rw-r--r--py/mock/util.py85
11 files changed, 232 insertions, 151 deletions
diff --git a/docs/mock.1 b/docs/mock.1
index e6a501d..cc29ee4 100644
--- a/docs/mock.1
+++ b/docs/mock.1
@@ -74,7 +74,7 @@ Disable configure OPTION for build. This option may be used multiple times. Fo
\fB\-\-resultdir=\fR\fIRESULTDIR\fP
Change directory where resulting files (RPMs and build logs) are written. Resultdir can contain python-string substitutions for any variable in the chroot config. For example:
-\fB\-\-resultdir=./my/'%(dist)s'/'%(target_arch)s'/\fR
+\fB\-\-resultdir=./my/"%(dist)s"/"%(target_arch)s"/\fR
.TP
\fB\-\-uniqueext=\fR\fItext\fP
Arbitrary, unique extension to append to buildroot directory name
diff --git a/etc/mock/logging.ini b/etc/mock/logging.ini
index 7b193e2..fadc6a8 100644
--- a/etc/mock/logging.ini
+++ b/etc/mock/logging.ini
@@ -18,7 +18,7 @@ format: %(levelname)s: %(message)s
;useful for debugging:
[formatter_detailed]
-format: %(asctime)s - %(levelname)s %(filename)s, Line: %(lineno)d: %(message)s
+format: %(levelname)s %(filename)s:%(lineno)d: %(message)s
[handler_unadorned_console]
class: StreamHandler
diff --git a/py/mock.py b/py/mock.py
index 6b520f7..f6797b9 100755
--- a/py/mock.py
+++ b/py/mock.py
@@ -34,6 +34,7 @@ import logging
import logging.config
import os
import os.path
+import pwd
import sys
import time
from optparse import OptionParser
@@ -131,6 +132,8 @@ def command_parse(config_opts):
dest="verbose", default=1, help="verbose build")
parser.add_option("-q", "--quiet", action="store_const", const=0,
dest="verbose", help="quiet build")
+ parser.add_option("--trace", action="store_true", default=False,
+ dest="trace", help="quiet build")
# plugins
parser.add_option("--enable-plugin", action="append",
@@ -150,8 +153,8 @@ def command_parse(config_opts):
return (options, args)
-decorate(traceLog(log))
-def setup_default_config_opts(config_opts):
+decorate(traceLog())
+def setup_default_config_opts(config_opts, unprivUid):
"sets up default configuration."
# global
config_opts['basedir'] = '/var/lib/mock/' # root name is automatically added to this
@@ -161,7 +164,7 @@ def setup_default_config_opts(config_opts):
config_opts['chroothome'] = '/builddir'
config_opts['log_config_file'] = 'logging.ini'
config_opts['rpmbuild_timeout'] = 0
- config_opts['chrootuid'] = os.getuid()
+ config_opts['chrootuid'] = unprivUid
try:
config_opts['chrootgid'] = grp.getgrnam("mock")[2]
except KeyError:
@@ -221,7 +224,7 @@ def setup_default_config_opts(config_opts):
'%_rpmfilename': '%%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm',
}
-decorate(traceLog(log))
+decorate(traceLog())
def set_config_opts_per_cmdline(config_opts, options, args):
"takes processed cmdline args and sets config options."
# do some other options and stuff
@@ -290,7 +293,7 @@ def set_config_opts_per_cmdline(config_opts, options, args):
config_opts['online'] = options.online
-decorate(traceLog(log))
+decorate(traceLog())
def do_rebuild(config_opts, chroot, srpms):
"rebuilds a list of srpms using provided chroot"
if len(srpms) < 1:
@@ -338,22 +341,34 @@ def main(ret):
# setuid wrapper has real uid = unpriv, effective uid = 0
# sudo sets real/effective = 0, and sets env vars
# setuid wrapper clears environment, so there wont be any conflict between these two
+
+ # old setuid wrapper
unprivUid = os.getuid()
+ unprivGid = os.getgid()
+
+ # sudo
if os.environ.get("SUDO_UID") is not None:
unprivUid = int(os.environ['SUDO_UID'])
- groups = [ g[2] for g in grp.getgrall() if os.environ.get("SUDO_USER") in g[3]]
+ username = os.environ.get("SUDO_USER")
+ groups = [ g[2] for g in grp.getgrall() if username in g[3]]
os.setgroups(groups)
- unprivGid = os.getgid()
- if os.environ.get("SUDO_GID") is not None:
unprivGid = int(os.environ['SUDO_GID'])
+ # consolehelper
+ if os.environ.get("USERHELPER_UID") is not None:
+ unprivUid = int(os.environ['USERHELPER_UID'])
+ username = pwd.getpwuid(unprivUid)[0]
+ groups = [ g[2] for g in grp.getgrall() if username in g[3]]
+ os.setgroups(groups)
+ unprivGid = pwd.getpwuid(unprivUid)[3]
+
uidManager = mock.uid.uidManager(unprivUid, unprivGid)
uidManager._becomeUser(unprivUid, unprivGid)
del(os.environ["HOME"])
# defaults
config_opts = {}
- setup_default_config_opts(config_opts)
+ setup_default_config_opts(config_opts, unprivUid)
(options, args) = command_parse(config_opts)
# config path -- can be overridden on cmdline
@@ -401,20 +416,27 @@ def main(ret):
log.handlers[0].setLevel(logging.INFO)
elif options.verbose == 2:
log.handlers[0].setLevel(logging.DEBUG)
- build_log = logging.getLogger("mock.Root.build")
- build_log.propagate = 1
- mock_log = logging.getLogger("mock")
- mock_log.propagate = 1
+ logging.getLogger("mock.Root.build").propagate = 1
+ logging.getLogger("mock").propagate = 1
+
+ logging.getLogger("trace").propagate=0
+ if options.trace:
+ logging.getLogger("trace").propagate=1
# cmdline options override config options
- log.info("mock.py version %s starting..." % __VERSION__)
set_config_opts_per_cmdline(config_opts, options, args)
+
+ # elevate privs
+ uidManager._becomeUser(0, 0)
# do whatever we're here to do
+ log.info("mock.py version %s starting..." % __VERSION__)
chroot = mock.backend.Root(config_opts, uidManager)
- # elevate privs
- uidManager._becomeUser(0, 0)
+ # dump configuration to log
+ log.debug("mock final configuration:")
+ for k, v in config_opts.items():
+ log.debug(" %s: %s" % (k, v))
ret["chroot"] = chroot
ret["config_opts"] = config_opts
@@ -422,6 +444,12 @@ def main(ret):
if options.mode not in ('chroot', 'shell', 'install', 'installdeps') and config_opts['clean']:
chroot.clean()
+ # New namespace starting from here
+ try:
+ mock.util.unshare(mock.util.CLONE_NEWNS)
+ except:
+ log.info("Namespace unshare failed.")
+
if options.mode == 'init':
chroot.init()
diff --git a/py/mock/backend.py b/py/mock/backend.py
index 2484457..98c1a52 100644
--- a/py/mock/backend.py
+++ b/py/mock/backend.py
@@ -17,15 +17,12 @@ import stat
# our imports
import mock.util
import mock.exception
-from mock.trace_decorator import traceLog, decorate
-
-# set up logging
-moduleLog = logging.getLogger("mock")
+from mock.trace_decorator import traceLog, decorate, getLog
# classes
class Root(object):
"""controls setup of chroot environment"""
- decorate(traceLog(moduleLog))
+ decorate(traceLog())
def __init__(self, config, uidManager):
self._state = 'unstarted'
self.uidManager = uidManager
@@ -53,9 +50,9 @@ class Root(object):
# result dir
self.resultdir = config['resultdir'] % config
- self.root_log = logging.getLogger("mock")
- self.build_log = logging.getLogger("mock.Root.build")
- self._state_log = logging.getLogger("mock.Root.state")
+ self.root_log = getLog("mock")
+ self.build_log = getLog("mock.Root.build")
+ self._state_log = getLog("mock.Root.state")
# config options
self.chrootuid = config['chrootuid']
@@ -106,14 +103,14 @@ class Root(object):
# =============
# 'Public' API
# =============
- decorate(traceLog(moduleLog))
+ decorate(traceLog())
def addHook(self, stage, function):
hooks = self._hooks.get(stage, [])
if function not in hooks:
hooks.append(function)
self._hooks[stage] = hooks
- decorate(traceLog(moduleLog))
+ decorate(traceLog())
def state(self, newState = None):
if newState is not None:
self._state = newState
@@ -121,7 +118,7 @@ class Root(object):
return self._state
- decorate(traceLog(moduleLog))
+ decorate(traceLog())
def clean(self):
"""clean out chroot with extreme prejudice :)"""
self.tryLockBuildRoot()
@@ -129,7 +126,7 @@ class Root(object):
mock.util.rmtree(self.basedir)
self.chrootWasCleaned = True
- decorate(traceLog(moduleLog))
+ decorate(traceLog())
def tryLockBuildRoot(self):
self.state("lock buildroot")
try:
@@ -144,7 +141,7 @@ class Root(object):
return 1
- decorate(traceLog(moduleLog))
+ decorate(traceLog())
def init(self):
self.state("init")
@@ -254,7 +251,7 @@ class Root(object):
# done with init
self._callHooks('postinit')
- decorate(traceLog(moduleLog))
+ decorate(traceLog())
def _setupDev(self):
# files in /dev
mock.util.rmtree(os.path.join(self.rootdir, "dev"))
@@ -291,12 +288,12 @@ class Root(object):
if mntCmd not in self.mountCmds:
self.mountCmds.append(mntCmd)
- decorate(traceLog(moduleLog))
+ decorate(traceLog())
def doChroot(self, command, env="", *args, **kargs):
"""execute given command in root"""
return mock.util.do( command, personality=self.personality, chrootPath=self.rootdir, *args, **kargs )
- decorate(traceLog(moduleLog))
+ decorate(traceLog())
def yumInstall(self, *srpms):
"""figure out deps from srpm. call yum to install them"""
# pass build reqs (as strings) to installer
@@ -306,7 +303,7 @@ class Root(object):
finally:
self._umountall()
- decorate(traceLog(moduleLog))
+ decorate(traceLog())
def installSrpmDeps(self, *srpms):
"""figure out deps from srpm. call yum to install them"""
arg_string = self.preExistingDeps
@@ -342,7 +339,7 @@ class Root(object):
# Everything in this function runs as the build user
# -> except hooks. :)
#
- decorate(traceLog(moduleLog))
+ decorate(traceLog())
def build(self, srpm, timeout):
"""build an srpm into binary rpms, capture log"""
@@ -423,13 +420,13 @@ class Root(object):
# =============
# 'Private' API
# =============
- decorate(traceLog(moduleLog))
+ decorate(traceLog())
def _callHooks(self, stage):
hooks = self._hooks.get(stage, [])
for hook in hooks:
hook()
- decorate(traceLog(moduleLog))
+ decorate(traceLog())
def _initPlugins(self):
# Import plugins (simplified copy of what yum does). Can add yum
# features later when we prove we need them.
@@ -446,21 +443,21 @@ class Root(object):
module.init(self, self.pluginConf["%s_opts" % modname])
- decorate(traceLog(moduleLog))
+ decorate(traceLog())
def _mountall(self):
"""mount 'normal' fs like /dev/ /proc/ /sys"""
for cmd in self.mountCmds:
self.root_log.debug(cmd)
mock.util.do(cmd)
- decorate(traceLog(moduleLog))
+ decorate(traceLog())
def _umountall(self):
"""umount all mounted chroot fs."""
for cmd in self.umountCmds:
self.root_log.debug(cmd)
mock.util.do(cmd, raiseExc=0)
- decorate(traceLog(moduleLog))
+ decorate(traceLog())
def _yum(self, cmd, returnOutput=0):
"""use yum to install packages/package groups into the chroot"""
# mock-helper yum --installroot=rootdir cmd
@@ -479,7 +476,7 @@ class Root(object):
except mock.exception.Error, e:
raise mock.exception.YumError, str(e)
- decorate(traceLog(moduleLog))
+ decorate(traceLog())
def _makeBuildUser(self):
if not os.path.exists(os.path.join(self.rootdir, 'usr/sbin/useradd')):
raise mock.exception.RootError, "Could not find useradd in chroot, maybe the install failed?"
@@ -495,32 +492,38 @@ class Root(object):
self.doChroot(self.useradd % dets)
self.doChroot("perl -p -i -e 's/^(%s:)!!/$1/;' /etc/passwd" % (self.chrootuser), raiseExc=True)
- decorate(traceLog(moduleLog))
+ decorate(traceLog())
def _resetLogging(self):
# ensure we dont attach the handlers multiple times.
if self.logging_initialized:
return
self.logging_initialized = True
- # attach logs to log files.
- # This happens in addition to anything that
- # is set up in the config file... ie. logs go everywhere
- for (log, filename, fmt_str) in (
- (self._state_log, "state.log", self._state_log_fmt_str),
- (self.build_log, "build.log", self.build_log_fmt_str),
- (self.root_log, "root.log", self.root_log_fmt_str)):
- fullPath = os.path.join(self.resultdir, filename)
- fh = logging.FileHandler(fullPath, "a+")
- formatter = logging.Formatter(fmt_str)
- fh.setFormatter(formatter)
- fh.setLevel(logging.NOTSET)
- log.addHandler(fh)
+ try:
+ self.uidManager.dropPrivsTemp()
+
+ # attach logs to log files.
+ # This happens in addition to anything that
+ # is set up in the config file... ie. logs go everywhere
+ for (log, filename, fmt_str) in (
+ (self._state_log, "state.log", self._state_log_fmt_str),
+ (self.build_log, "build.log", self.build_log_fmt_str),
+ (self.root_log, "root.log", self.root_log_fmt_str)):
+ fullPath = os.path.join(self.resultdir, filename)
+ fh = logging.FileHandler(fullPath, "a+")
+ formatter = logging.Formatter(fmt_str)
+ fh.setFormatter(formatter)
+ fh.setLevel(logging.NOTSET)
+ log.addHandler(fh)
+ finally:
+ self.uidManager.restorePrivs()
+
#
# UNPRIVLEGED:
# Everything in this function runs as the build user
#
- decorate(traceLog(moduleLog))
+ decorate(traceLog())
def _buildDirSetup(self):
# create all dirs as the user who will be dropping things there.
self.uidManager.becomeUser(self.chrootuid, self.chrootgid)
@@ -549,7 +552,7 @@ class Root(object):
# UNPRIVLEGED:
# Everything in this function runs as the build user
#
- decorate(traceLog(moduleLog))
+ decorate(traceLog())
def _copySrpmIntoChroot(self, srpm):
srpmFilename = os.path.basename(srpm)
dest = self.rootdir + '/' + self.builddir + '/' + 'originals'
diff --git a/py/mock/plugins/bind_mount.py b/py/mock/plugins/bind_mount.py
index 7b9cfe3..60f0f8b 100644
--- a/py/mock/plugins/bind_mount.py
+++ b/py/mock/plugins/bind_mount.py
@@ -4,25 +4,24 @@
# Copyright (C) 2007 Michael E Brown <mebrown@michaels-house.net>
# python library imports
-import logging
import os
# our imports
-from mock.trace_decorator import traceLog
+from mock.trace_decorator import decorate, traceLog, getLog
+
import mock.util
-# set up logging, module options
-moduleLog = logging.getLogger("mock")
requires_api_version = "1.0"
# plugin entry point
+decorate(traceLog())
def init(rootObj, conf):
BindMount(rootObj, conf)
# classes
class BindMount(object):
"""bind mount dirs from host into chroot"""
- @traceLog(moduleLog)
+ decorate(traceLog())
def __init__(self, rootObj, conf):
self.rootObj = rootObj
self.bind_opts = conf
@@ -33,7 +32,7 @@ class BindMount(object):
rootObj.umountCmds.append('umount -n %s/%s' % (rootObj.rootdir, destdir))
rootObj.mountCmds.append('mount -n --bind %s %s/%s' % (srcdir, rootObj.rootdir, destdir))
- @traceLog(moduleLog)
+ decorate(traceLog())
def _bindMountPreInitHook(self):
for srcdir, destdir in self.bind_opts['dirs']:
mock.util.mkdirIfAbsent("%s/%s" % (self.rootObj.rootdir, destdir))
diff --git a/py/mock/plugins/ccache.py b/py/mock/plugins/ccache.py
index 489f7a0..7974b1f 100644
--- a/py/mock/plugins/ccache.py
+++ b/py/mock/plugins/ccache.py
@@ -4,25 +4,23 @@
# Copyright (C) 2007 Michael E Brown <mebrown@michaels-house.net>
# python library imports
-import logging
import os
# our imports
-from mock.trace_decorator import traceLog
+from mock.trace_decorator import decorate, traceLog, getLog
import mock.util
-# set up logging, module options
-moduleLog = logging.getLogger("mock")
requires_api_version = "1.0"
# plugin entry point
+decorate(traceLog())
def init(rootObj, conf):
CCache(rootObj, conf)
# classes
class CCache(object):
"""enables ccache in buildroot/rpmbuild"""
- @traceLog(moduleLog)
+ decorate(traceLog())
def __init__(self, rootObj, conf):
self.rootObj = rootObj
self.ccache_opts = conf
@@ -40,7 +38,7 @@ class CCache(object):
# =============
# set the max size before we actually use it during a build.
# ccache itself manages size and settings.
- @traceLog(moduleLog)
+ decorate(traceLog())
def _ccacheBuildHook(self):
self.rootObj.doChroot("ccache -M %s" % self.ccache_opts['max_cache_size'])
@@ -49,7 +47,7 @@ class CCache(object):
# we then add this to the front of the path.
# we also set a few admin variables used by ccache to find the shared
# cache.
- @traceLog(moduleLog)
+ decorate(traceLog())
def _ccachePreInitHook(self):
mock.util.mkdirIfAbsent(os.path.join(self.rootdir, 'tmp/ccache'))
mock.util.mkdirIfAbsent(self.ccachePath)
@@ -63,7 +61,7 @@ class CCache(object):
forceLink("/usr/bin/ccache", os.path.join(self.ccachePath, "x86_64-redhat-linux-%s" % i))
forceLink("/usr/bin/ccache", os.path.join(self.ccachePath, "i386-redhat-linux-%s" % i))
-@traceLog(moduleLog)
+decorate(traceLog())
def forceLink( existing, linkname ):
try:
os.unlink(linkname)
diff --git a/py/mock/plugins/root_cache.py b/py/mock/plugins/root_cache.py
index 6f54858..5082925 100644
--- a/py/mock/plugins/root_cache.py
+++ b/py/mock/plugins/root_cache.py
@@ -5,26 +5,24 @@
# python library imports
import fcntl
-import logging
import os
import time
# our imports
-from mock.trace_decorator import traceLog
+from mock.trace_decorator import decorate, traceLog, getLog
import mock.util
-# set up logging, module options
-moduleLog = logging.getLogger("mock")
requires_api_version = "1.0"
# plugin entry point
+decorate(traceLog())
def init(rootObj, conf):
RootCache(rootObj, conf)
# classes
class RootCache(object):
"""caches root environment in a tarball"""
- @traceLog(moduleLog)
+ decorate(traceLog())
def __init__(self, rootObj, conf):
self.rootObj = rootObj
self.root_cache_opts = conf
@@ -40,7 +38,7 @@ class RootCache(object):
# =============
# 'Private' API
# =============
- @traceLog(moduleLog)
+ decorate(traceLog())
def _rootCacheLock(self, shared=1):
lockType = fcntl.LOCK_EX
if shared: lockType = fcntl.LOCK_SH
@@ -52,13 +50,13 @@ class RootCache(object):
fcntl.lockf(self.rootCacheLock.fileno(), lockType)
self.state(oldState)
- @traceLog(moduleLog)
+ decorate(traceLog())
def _rootCacheUnlock(self):
fcntl.lockf(self.rootCacheLock.fileno(), fcntl.LOCK_UN)
- @traceLog(moduleLog)
+ decorate(traceLog())
def _rootCachePreInitHook(self):
- moduleLog.info("enabled root cache")
+ getLog().info("enabled root cache")
mock.util.mkdirIfAbsent(self.rootSharedCachePath)
# lock so others dont accidentally use root cache while we operate on it.
if self.rootCacheLock is None:
@@ -82,7 +80,7 @@ class RootCache(object):
self.chroot_setup_cmd = "update"
self.rootObj.chrootWasCleaned = False
- @traceLog(moduleLog)
+ decorate(traceLog())
def _rootCachePostInitHook(self):
# never rebuild cache unless it was a clean build.
if self.rootObj.chrootWasCleaned:
diff --git a/py/mock/plugins/yum_cache.py b/py/mock/plugins/yum_cache.py
index ed73a9d..5b371bb 100644
--- a/py/mock/plugins/yum_cache.py
+++ b/py/mock/plugins/yum_cache.py
@@ -10,21 +10,21 @@ import time
import os
# our imports
-from mock.trace_decorator import traceLog
+from mock.trace_decorator import decorate, traceLog, getLog
import mock.util
# set up logging, module options
-moduleLog = logging.getLogger("mock")
requires_api_version = "1.0"
# plugin entry point
+decorate(traceLog())
def init(rootObj, conf):
YumCache(rootObj, conf)
# classes
class YumCache(object):
"""caches root environment in a tarball"""
- @traceLog(moduleLog)
+ decorate(traceLog())
def __init__(self, rootObj, conf):
self.rootObj = rootObj
self.yum_cache_opts = conf
@@ -48,7 +48,7 @@ class YumCache(object):
# by yum, and prior to cleaning it. This prevents simultaneous access from
# screwing things up. This can possibly happen, eg. when running multiple
# mock instances with --uniqueext=
- @traceLog(moduleLog)
+ decorate(traceLog())
def _yumCachePreYumHook(self):
try:
fcntl.lockf(self.yumCacheLock.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
@@ -58,13 +58,13 @@ class YumCache(object):
fcntl.lockf(self.yumCacheLock.fileno(), fcntl.LOCK_EX)
self.state(oldState)
- @traceLog(moduleLog)
+ decorate(traceLog())
def _yumCachePostYumHook(self):
fcntl.lockf(self.yumCacheLock.fileno(), fcntl.LOCK_UN)
- @traceLog(moduleLog)
+ decorate(traceLog())
def _yumCachePreInitHook(self):
- moduleLog.info("enabled yum cache")
+ getLog().info("enabled yum cache")
mock.util.mkdirIfAbsent(os.path.join(self.rootdir, 'var/cache/yum'))
# lock so others dont accidentally use yum cache while we operate on it.
diff --git a/py/mock/trace_decorator.py b/py/mock/trace_decorator.py
index e761e1e..05c340c 100755
--- a/py/mock/trace_decorator.py
+++ b/py/mock/trace_decorator.py
@@ -6,9 +6,24 @@
import logging
import os
import sys
+import types
from peak.util.decorators import rewrap, decorate
-moduleLog = logging.getLogger("mock.trace_decorator")
+# defaults to module verbose log
+# does a late binding on log. Forwards all attributes to logger.
+# works around problem where reconfiguring the logging module means loggers
+# configured before reconfig dont output.
+class getLog(object):
+ def __init__(self, name=None, prefix="", *args, **kargs):
+ if name is None:
+ frame = sys._getframe(1)
+ name = frame.f_globals["__name__"]
+
+ self.name = prefix + name
+
+ def __getattr__(self, name):
+ logger = logging.getLogger(self.name)
+ return getattr(logger, name)
# emulates logic in logging module to ensure we only log
# messages that logger is enabled to produce.
@@ -22,57 +37,69 @@ def doLog(logger, level, *args, **kargs):
del(kargs["func"])
logger.handle(logger.makeRecord(logger.name, level, *args, **kargs))
-
-def traceLog(log = moduleLog):
+def traceLog(log = None):
def decorator(func):
def trace(*args, **kw):
# default to logger that was passed by module, but
# can override by passing logger=foo as function parameter.
# make sure this doesnt conflict with one of the parameters
# you are expecting
-
+
filename = os.path.normcase(func.func_code.co_filename)
func_name = func.func_code.co_name
lineno = func.func_code.co_firstlineno
-
+
l2 = kw.get('logger', log)
+ if l2 is None:
+ l2 = logging.getLogger("trace.%s" % func.__module__)
+ if isinstance(l2, basestring):
+ l2 = logging.getLogger(l2)
+
message = "ENTER %s(" % func_name
for arg in args:
message = message + repr(arg) + ", "
- for k, v in kw.items():
- message = message + "%s=%s" % (k, repr(v))
+ for k,v in kw.items():
+ message = message + "%s=%s" % (k,repr(v))
message = message + ")"
-
+
frame = sys._getframe(2)
- doLog(l2, logging.DEBUG, os.path.normcase(frame.f_code.co_filename), frame.f_lineno, message, args=[], exc_info=None, func=frame.f_code.co_name)
+ doLog(l2, logging.INFO, os.path.normcase(frame.f_code.co_filename), frame.f_lineno, message, args=[], exc_info=None, func=frame.f_code.co_name)
try:
result = "Bad exception raised: Exception was not a derived class of 'Exception'"
try:
result = func(*args, **kw)
except (KeyboardInterrupt, Exception), e:
result = "EXCEPTION RAISED"
- doLog(l2, logging.DEBUG, filename, lineno, "EXCEPTION: %s\n" % e, args=[], exc_info=sys.exc_info(), func=func_name)
+ doLog(l2, logging.INFO, filename, lineno, "EXCEPTION: %s\n" % e, args=[], exc_info=sys.exc_info(), func=func_name)
raise
finally:
- doLog(l2, logging.DEBUG, filename, lineno, "LEAVE %s --> %s\n" % (func_name, result), args=[], exc_info=None, func=func_name)
+ doLog(l2, logging.INFO, filename, lineno, "LEAVE %s --> %s\n" % (func_name, result), args=[], exc_info=None, func=func_name)
return result
return rewrap(func, trace)
return decorator
+# helper function so we can use back-compat format but not be ugly
+def decorateAllFunctions(module, logger=None):
+ methods = [ method for method in dir(module)
+ if isinstance(getattr(module, method), types.FunctionType)
+ ]
+ for i in methods:
+ setattr(module, i, traceLog(logger)(getattr(module,i)))
+
# unit tests...
if __name__ == "__main__":
logging.basicConfig(level=logging.WARNING,
format='%(name)s %(levelname)s %(filename)s, %(funcName)s, Line: %(lineno)d: %(message)s',)
- log = logging.getLogger("foobar.bubble")
- root = logging.getLogger()
+ log = getLog("foobar.bubble")
+ root = getLog(name="")
log.setLevel(logging.WARNING)
root.setLevel(logging.DEBUG)
log.debug(" --> debug")
log.error(" --> error")
- @traceLog(log)
+ decorate(traceLog(log))
def testFunc(arg1, arg2="default", *args, **kargs):
return 42
@@ -80,9 +107,24 @@ if __name__ == "__main__":
testFunc("happy", "joy", name="skippy")
testFunc("hi")
- @traceLog(root)
+ decorate(traceLog(root))
def testFunc22():
return testFunc("archie", "bunker")
testFunc22()
+ decorate(traceLog(root))
+ def testGen():
+ yield 1
+ yield 2
+
+ for i in testGen():
+ log.debug("got: %s" % i)
+
+ decorate(traceLog())
+ def anotherFunc(*args):
+ return testFunc(*args)
+
+ anotherFunc("pretty")
+
+ getLog()
diff --git a/py/mock/uid.py b/py/mock/uid.py
index 0d12935..5729d5c 100644
--- a/py/mock/uid.py
+++ b/py/mock/uid.py
@@ -4,36 +4,32 @@
# Copyright (C) 2007 Michael E Brown <mebrown@michaels-house.net>
# python library imports
-import logging
import os
# our imports
-from mock.trace_decorator import traceLog, decorate
-
-# set up logging
-log = logging.getLogger("mock.uid")
+from mock.trace_decorator import traceLog, decorate, getLog
# class
class uidManager(object):
- decorate(traceLog(log))
+ decorate(traceLog())
def __init__(self, unprivUid=-1, unprivGid=-1):
self.privStack = []
self.unprivUid = unprivUid
self.unprivGid = unprivGid
- decorate(traceLog(log))
+ decorate(traceLog())
def becomeUser(self, uid, gid=-1):
# save current ruid, euid, rgid, egid
self._push()
self._becomeUser(uid, gid)
- decorate(traceLog(log))
+ decorate(traceLog())
def dropPrivsTemp(self):
# save current ruid, euid, rgid, egid
self._push()
self._becomeUser(self.unprivUid, self.unprivGid)
- decorate(traceLog(log))
+ decorate(traceLog())
def restorePrivs(self):
# back to root first
self._elevatePrivs()
@@ -43,13 +39,13 @@ class uidManager(object):
os.setregid(privs['rgid'], privs['egid'])
setresuid(privs['ruid'], privs['euid'])
- decorate(traceLog(log))
+ decorate(traceLog())
def dropPrivsForever(self):
self._elevatePrivs()
os.setregid(self.unprivGid, self.unprivGid)
os.setreuid(self.unprivUid, self.unprivUid)
- decorate(traceLog(log))
+ decorate(traceLog())
def _push(self):
# save current ruid, euid, rgid, egid
self.privStack.append({
@@ -59,12 +55,12 @@ class uidManager(object):
"egid": os.getegid(),
})
- decorate(traceLog(log))
+ decorate(traceLog())
def _elevatePrivs(self):
setresuid(0, 0, 0)
os.setregid(0, 0)
- decorate(traceLog(log))
+ decorate(traceLog())
def _becomeUser(self, uid, gid=None):
self._elevatePrivs()
if gid is not None:
diff --git a/py/mock/util.py b/py/mock/util.py
index 32bbc7e..ee40994 100644
--- a/py/mock/util.py
+++ b/py/mock/util.py
@@ -6,7 +6,6 @@
# Copyright (C) 2007 Michael E Brown <mebrown@michaels-house.net>
# python library imports
-import logging
import os
import os.path
import popen2
@@ -19,10 +18,7 @@ import time
# our imports
import mock.exception
-from mock.trace_decorator import traceLog, decorate
-
-# set up logging
-log = logging.getLogger("mock.util")
+from mock.trace_decorator import traceLog, decorate, getLog
# classes
class commandTimeoutExpired(mock.exception.Error):
@@ -32,30 +28,31 @@ class commandTimeoutExpired(mock.exception.Error):
self.resultcode = 10
# functions
-decorate(traceLog(log))
+decorate(traceLog())
def mkdirIfAbsent(*args):
for dirName in args:
- log.debug("ensuring that dir exists: %s" % dirName)
+ getLog().debug("ensuring that dir exists: %s" % dirName)
if not os.path.exists(dirName):
try:
- log.debug("creating dir: %s" % dirName)
+ getLog().debug("creating dir: %s" % dirName)
os.makedirs(dirName)
except OSError, e:
- log.exception("Could not create dir %s. Error: %s" % (dirName, e))
+ getLog().exception("Could not create dir %s. Error: %s" % (dirName, e))
raise mock.exception.Error, "Could not create dir %s. Error: %s" % (dirName, e)
-decorate(traceLog(log))
+decorate(traceLog())
def touch(fileName):
- log.debug("touching file: %s" % fileName)
+ getLog().debug("touching file: %s" % fileName)
fo = open(fileName, 'w')
fo.close()
-decorate(traceLog(log))
+decorate(traceLog())
def rmtree(path, *args, **kargs):
"""version os shutil.rmtree that ignores no-such-file-or-directory errors,
and tries harder if it finds immutable files"""
tryAgain = 1
failedFilename = None
+ getLog().debug("remove tree: %s" % path)
while tryAgain:
tryAgain = 0
try:
@@ -72,20 +69,21 @@ def rmtree(path, *args, **kargs):
else:
raise
-decorate(traceLog(log))
+decorate(traceLog())
def orphansKill(rootToKill):
"""kill off anything that is still chrooted."""
+ getLog().debug("kill orphans")
for fn in os.listdir("/proc"):
try:
root = os.readlink("/proc/%s/root" % fn)
if root == rootToKill:
- log.warning("Process ID %s still running in chroot. Killing..." % fn)
+ getLog().warning("Process ID %s still running in chroot. Killing..." % fn)
os.kill(int(fn, 10), 15)
except OSError, e:
pass
-decorate(traceLog(log))
+decorate(traceLog())
def yieldSrpmHeaders(srpms, plainRpmOk=0):
ts = rpmUtils.transaction.initReadOnlyTransaction()
for srpm in srpms:
@@ -99,7 +97,7 @@ def yieldSrpmHeaders(srpms, plainRpmOk=0):
yield hdr
-decorate(traceLog(log))
+decorate(traceLog())
def requiresTextFromHdr(hdr):
"""take a header and hand back a unique'd list of the requires as
strings"""
@@ -120,7 +118,7 @@ def requiresTextFromHdr(hdr):
return rpmUtils.miscutils.unique(reqlist)
-decorate(traceLog(log))
+decorate(traceLog())
def getNEVRA(hdr):
name = hdr[rpm.RPMTAG_NAME]
ver = hdr[rpm.RPMTAG_VERSION]
@@ -130,7 +128,7 @@ def getNEVRA(hdr):
if epoch is None: epoch = 0
return (name, epoch, ver, rel, arch)
-decorate(traceLog(log))
+decorate(traceLog())
def getAddtlReqs(hdr, conf):
# Add the 'more_buildreqs' for this SRPM (if defined in config file)
(name, epoch, ver, rel, arch) = getNEVRA(hdr)
@@ -148,29 +146,30 @@ def getAddtlReqs(hdr, conf):
return rpmUtils.miscutils.unique(reqlist)
-decorate(traceLog(log))
+decorate(traceLog())
def uniqReqs(*args):
master = []
for l in args:
master.extend(l)
return rpmUtils.miscutils.unique(master)
-decorate(traceLog(log))
+decorate(traceLog())
def condChroot(chrootPath, uidManager=None):
if chrootPath is not None:
+ getLog().debug("chroot %s" % chrootPath)
if uidManager:
- log.debug("elevate privs to run chroot")
+ getLog().debug("elevate privs to run chroot")
uidManager.becomeUser(0)
os.chdir(chrootPath)
os.chroot(chrootPath)
if uidManager:
- log.debug("back to other privs")
+ getLog().debug("back to other privs")
uidManager.restorePrivs()
-decorate(traceLog(log))
+decorate(traceLog())
def condDropPrivs(uidManager, uid, gid):
if uidManager is not None:
- log.debug("about to drop privs")
+ getLog().debug("about to drop privs")
if uid is not None:
uidManager.unprivUid = uid
if gid is not None:
@@ -191,14 +190,33 @@ personality_defs['ppc64'] = 0x0000
personality_defs['i386'] = 0x0008
personality_defs['ppc'] = 0x0008
-decorate(traceLog(log))
+import ctypes
+_libc = ctypes.cdll.LoadLibrary("libc.so.6")
+_errno = ctypes.c_int.in_dll(_libc, "errno")
+_libc.personality.argtypes = [ctypes.c_ulong]
+_libc.personality.restype = ctypes.c_int
+
+decorate(traceLog())
def condPersonality(per=None):
if personality_defs.get(per, None) is None: return
- import ctypes
- _libc = ctypes.cdll.LoadLibrary("libc.so.6")
- _libc.personality.argtypes = [ctypes.c_ulong]
- _libc.personality.restype = ctypes.c_int
- _libc.personality(personality_defs[per])
+ res = _libc.personality(personality_defs[per])
+ if res:
+ raise OSError(_errno.value, os.strerror(_errno.value))
+ getLog().debug("set personality (setarch)")
+
+CLONE_NEWNS = 0x00020000
+
+decorate(traceLog())
+def unshare(flags):
+ getLog().debug("Unsharing. Flags: %s" % flags)
+ try:
+ _libc.unshare.argtypes = [ctypes.c_int,]
+ _libc.unshare.restype = ctypes.c_int
+ res = _libc.unshare(flags)
+ if res:
+ raise OSError(_errno.value, os.strerror(_errno.value))
+ except AttributeError, e:
+ pass
# logger =
# output = [1|0]
@@ -206,18 +224,17 @@ def condPersonality(per=None):
#
# Warning: this is the function from hell. :(
#
-decorate(traceLog(log))
+decorate(traceLog())
def do(command, chrootPath=None, timeout=0, raiseExc=True, returnOutput=0, uidManager=None, uid=None, gid=None, personality=None, *args, **kargs):
"""execute given command outside of chroot"""
- logger = kargs.get("logger", log)
- logger.debug("Run cmd: %s" % command)
+ logger = kargs.get("logger", getLog())
+ logger.debug("run cmd timeout(%s): %s" % (timeout, command))
def alarmhandler(signum, stackframe):
raise commandTimeoutExpired("Timeout(%s) exceeded for command: %s" % (timeout, command))
retval = 0
- logger.debug("Executing timeout(%s): %s" % (timeout, command))
output = ""
(r, w) = os.pipe()