Skip to content

Commit

Permalink
Add simple cleanup mechanism.
Browse files Browse the repository at this point in the history
  • Loading branch information
alenz33 committed Mar 30, 2015
1 parent e71d782 commit bba0606
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 35 deletions.
11 changes: 7 additions & 4 deletions conduct.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,12 @@ def parseArgv(argv):

return parser.parse_args(argv)

def initLogging(logname, daemonize=False):
def initLogging(daemonize=False):
globalcfg = conduct.cfg['conduct']

conduct.log = logging.getLogger(logname)
logging.Logger.manager.setLoggerClass(loggers.ConductLogger)
# getChild necessary to get the correct logger class
conduct.log = logging.getLogger().getChild('conduct')
loglevel = loggers.LOGLEVELS[globalcfg['loglevel']]
conduct.log.setLevel(loglevel)

Expand All @@ -117,7 +119,7 @@ def initLogging(logname, daemonize=False):
conduct.log.addHandler(loggers.ColoredConsoleHandler())

# logfile for fg and bg process
conduct.log.addHandler(loggers.LogfileHandler(globalcfg['logdir'], logname))
conduct.log.addHandler(loggers.LogfileHandler(globalcfg['logdir'], 'conduct'))


def main(argv=None):
Expand All @@ -132,7 +134,7 @@ def main(argv=None):
args = parseArgv(argv[1:])

# configure logging
initLogging(args.chain)
initLogging()

chainDef = loadChainDefinition(args.chain)

Expand All @@ -146,6 +148,7 @@ def main(argv=None):
paramValues[param] = getattr(args, param)


conduct.log.info('Build chain: %s' % args.chain)
try:
chain = Chain(args.chain, paramValues)
chain.build()
Expand Down
44 changes: 39 additions & 5 deletions conduct/buildsteps.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ class BuildStep(object):
def __init__(self, name, paramValues, chain=None):
self.name = name
self.chain = chain # Maintain a reference to the chain (for refs)
self.wasRun = False

self._params = {}

Expand All @@ -159,17 +160,43 @@ def build(self):
try:
# execute actual build actions
self.run()
self.wasRun = True
except Exception as exc:
resultStr = 'FAILED'
self.log.exception(exc)

return False
raise
finally:
self.log.info('')
self.log.info('%s' % resultStr)
self.log.info('=' * 80)

return True
def cleanupBuild(self):
if not self.wasRun:
return

self.log.info('=' * 80)
self.log.info('Cleanup build step: %s' % self.name)
self.log.info(self.description)
self.log.info('-' * 80)

resultStr = 'SUCCESS'
try:
self.cleanup()
self.wasRun = False
except Exception as exc:
resultStr = 'FAILED'
self.log.exception(exc)

raise
finally:
self.log.info('')
self.log.info('%s' % resultStr)
self.log.info('=' * 80)


def cleanup(self):
pass


def run(self):
Expand All @@ -183,16 +210,17 @@ def doReadLoglevel(self):
return INVLOGLEVELS[level]

def _initLogger(self):
self.log = conduct.log.getChild(self.name)
if self.chain is not None:
self.log = self.chain.log.getChild(self.name)
else:
self.log = conduct.log.getChild(self.name)
self.log.setLevel(LOGLEVELS[self.loglevel])

def _applyParams(self, paramValues):
for name, value in paramValues.iteritems():
setattr(self, name, value)




class SystemCall(BuildStep):
'''
Build step to execute given shell command.
Expand Down Expand Up @@ -226,6 +254,8 @@ def run(self):
os.chdir(cwd)




class Config(BuildStep):
'''
Build step to read given configuration file.
Expand Down Expand Up @@ -319,6 +349,10 @@ def run(self):
os.makedirs(dest)
self.tmpdir = dest

def cleanup(self):
shutil.rmtree(self.tmpdir)



class RmPath(BuildStep):
parameters = {
Expand Down
15 changes: 13 additions & 2 deletions conduct/chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,29 @@ def __init__(self, name, paramValues):

self._chainDef = {}

self._initLogger()
self._loadChainDefinition()
self._applyParamValues(paramValues)


def build(self):
for step in self.steps.values():
step.build()
try:
for step in self.steps.values():
step.build()
except Exception as e:
self.log.error('BUILD FAILED')

for step in reversed(self.steps.values()):
step.cleanupBuild()


@property
def parameters(self):
return self._chainDef['parameters']

def _initLogger(self):
self.log = conduct.log.getChild(self.name, True)

def _applyParamValues(self, values):
for name, definition in self.parameters.iteritems():
if name in values:
Expand Down
64 changes: 46 additions & 18 deletions conduct/loggers.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import logging

from os import path
from logging import Formatter, Handler, DEBUG, INFO, WARNING, ERROR
from logging import Logger, Formatter, Handler, DEBUG, INFO, WARNING, ERROR

from conduct import colors

Expand All @@ -42,6 +42,30 @@
LOGLEVELS = {'debug': DEBUG, 'info': INFO, 'warning': WARNING, 'error': ERROR}
INVLOGLEVELS = {value : key for key, value in LOGLEVELS.iteritems()}

class ConductLogger(Logger):
def getChild(self, suffix, ownDir=False):
child = Logger.getChild(self, suffix)

if ownDir:
for handler in self._collectHandlers():
if isinstance(handler, LogfileHandler):
handler = handler.getChild(suffix)
child.addHandler(handler)

child.propagate = False

return child

def _collectHandlers(self):
result = []

log = self
while log is not None:
result += log.handlers
log = log.parent

return result


class ConsoleFormatter(Formatter):
"""
Expand Down Expand Up @@ -187,12 +211,12 @@ class LogfileHandler(StreamHandler):
"""

def __init__(self, directory, filenameprefix, dayfmt=DATESTAMP_FMT):
directory = path.join(directory, filenameprefix)
if not path.isdir(directory):
os.makedirs(directory)
self._currentsymlink = path.join(directory, 'current')
self._directory = path.join(directory, filenameprefix)
if not path.isdir(self._directory):
os.makedirs(self._directory)
self._currentsymlink = path.join(self._directory, 'current')
self._filenameprefix = filenameprefix
self._pathnameprefix = path.join(directory, filenameprefix)
self._pathnameprefix = path.join(self._directory, filenameprefix)
self._dayfmt = dayfmt
# today's logfile name
basefn = self._pathnameprefix + '-' + time.strftime(dayfmt) + '.log'
Expand All @@ -206,18 +230,9 @@ def __init__(self, directory, filenameprefix, dayfmt=DATESTAMP_FMT):
self.setFormatter(LogfileFormatter(LOGFMT, DATEFMT))
self.disabled = False

def _open(self):
# update 'current' symlink upon open
try:
os.remove(self._currentsymlink)
except OSError:
# if the symlink does not (yet) exist, OSError is raised.
# should happen at most once per installation....
pass
if hasattr(os, 'symlink'):
os.symlink(path.basename(self.baseFilename), self._currentsymlink)
# finally open the new logfile....
return open(self.baseFilename, self.mode)
def getChild(self, name):
return LogfileHandler(self._directory, name)


def filter(self, record):
return not self.disabled
Expand Down Expand Up @@ -260,6 +275,19 @@ def doRollover(self):
self.stream = self._open()
self.rollover_at += SECONDS_PER_DAY

def _open(self):
# update 'current' symlink upon open
try:
os.remove(self._currentsymlink)
except OSError:
# if the symlink does not (yet) exist, OSError is raised.
# should happen at most once per installation....
pass
if hasattr(os, 'symlink'):
os.symlink(path.basename(self.baseFilename), self._currentsymlink)
# finally open the new logfile....
return open(self.baseFilename, self.mode)


class ColoredConsoleHandler(StreamHandler):
"""
Expand Down
4 changes: 0 additions & 4 deletions etc/chains/frm2/boximg.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,4 @@
dev='{steps.tmpdir.tmpdir}/{chain.imgname}.img',
partitions=[3,5])

steps.cleanup = Step('conduct.RmPath',
description='Cleanup tmp dir',
path='{steps.tmpdir.tmpdir}')


4 changes: 2 additions & 2 deletions etc/conduct.conf
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[conduct]

logdir = /var/log/conduct
loglevel = debug
logdir = /var/log
loglevel = info

chaindefdir = etc/chains
chaincfgdir = etc/config

0 comments on commit bba0606

Please sign in to comment.