Compare commits

..

11 Commits

2 changed files with 66 additions and 37 deletions

View File

@ -47,6 +47,10 @@ def parse_args():
'-L', '--no-lock', '-L', '--no-lock',
help='Allow multiple simultanious executions of this cron job', help='Allow multiple simultanious executions of this cron job',
action='store_true') action='store_true')
parser.add_argument(
'-r', '--restart',
help='Restart the process if not running; exit with success if previous instance is running',
action='store_true')
parser.add_argument( parser.add_argument(
@ -79,7 +83,7 @@ def parse_args():
args = parser.parse_args() args = parser.parse_args()
if not args.name: if not args.name:
args.name = [os.path.basename(args.command[0])] args.name = os.path.basename(args.command[0])
return args return args
@ -104,7 +108,7 @@ def exec_command(args, outfile, errfile, resfile):
proc.terminate() proc.terminate()
proc.communicate(timeout=10) proc.communicate(timeout=10)
now=datetime.datetime.utcnow() now=datetime.datetime.now()
nowstr=now.strftime('%Y-%m-%d_%H%M.%S') nowstr=now.strftime('%Y-%m-%d_%H%M.%S')
resfile.write('{}\n{}'.format(nowstr, proc.returncode)) resfile.write('{}\n{}'.format(nowstr, proc.returncode))
return proc.returncode return proc.returncode
@ -159,60 +163,84 @@ def print_runs(runs, clean=True):
print("\n\n") print("\n\n")
if clean: if clean:
for run in runs: for run in runs:
shutil.rmtree(run) try:
shutil.rmtree(run)
except FileNotFoundError:
pass
def main(): def main():
time_format = '%Y-%m-%d_%H%M' time_format = '%Y-%m-%d_%H%M'
args = parse_args() args = parse_args()
now = datetime.datetime.utcnow() now = datetime.datetime.now()
nowstr = now.strftime(time_format) nowstr = now.strftime(time_format)
libdir = os.path.join(args.cachedir[0], args.name[0], nowstr) libdir = os.path.join(args.cachedir[0], args.name, nowstr)
lckdir = os.path.join(args.lockdir[0], args.name[0]) lckdir = os.path.join(args.lockdir[0], args.name)
os.makedirs(lckdir, exist_ok=True) os.makedirs(lckdir, exist_ok=True)
os.makedirs(libdir) os.makedirs(libdir)
lckfile = os.path.join(lckdir, args.name[0]) lckfile = os.path.join(lckdir, args.name)
outfile = os.path.join(libdir, 'stdout') outfile = os.path.join(libdir, 'stdout')
errfile = os.path.join(libdir, 'stderr') errfile = os.path.join(libdir, 'stderr')
resfile = os.path.join(libdir, 'result') resfile = os.path.join(libdir, 'result')
with open(outfile, 'w') as o, open(errfile, 'w') as e, open(resfile, 'w') as r: success = True
if args.no_lock or aquire_lock(lckfile): has_lock = True
with open(outfile, 'w') as o, open(errfile, 'w+') as e, open(resfile, 'w') as r:
if args.no_lock:
res = exec_command(args, o, e, r) res = exec_command(args, o, e, r)
else: else:
e.write("CRONWRAPPER: Unable to aquire lock, previous instance still running?\n") has_lock = aquire_lock(lckfile)
r.write("\nFalse\n") if has_lock:
res = False res = exec_command(args, o, e, r)
elif args.restart:
res = 0
else:
e.write("CRONWRAPPER: Unable to aquire lock, previous instance still running?\n")
r.write("\nFalse\n")
res = False
previous_runs = {} if res in args.success_exit_codes:
for root, dirs, files in os.walk(os.path.join(args.cachedir[0], args.name[0])): # Possible success, check error output
previous_runs = { re_checks = [re.compile(r) for r in args.ignore_error]
os.path.join(root, d): datetime.datetime.strptime(d, time_format) e.seek(0)
for d in dirs for line in e:
if datetime.datetime.strptime(d, time_format) < datetime.datetime.strptime(nowstr, time_format)} success = False
break
if res in args.success_exit_codes:
# Possible success, check error output
re_checks = [re.compile(r) for r in args.ignore_error]
ok = True
with open(errfile, 'r') as f:
for line in f:
ok = False
for r in re_checks: for r in re_checks:
if re.match(r, line): if re.match(r, line):
ok = True success = True
break break
if not ok: if not success:
break break
if ok: else:
# Yes! Success! report any errors until now success = False
if previous_runs:
print("Success after {} failed runs\n".format(len(previous_runs)))
print_runs(previous_runs.keys()) previous_runs = {}
for root, dirs, files in os.walk(os.path.join(args.cachedir[0], args.name)):
for d in dirs:
if datetime.datetime.strptime(d, time_format) < datetime.datetime.strptime(nowstr, time_format):
with open(os.path.join(root, d, 'result'), 'r') as f:
try:
retcode = f.read().splitlines()[-1]
except IndexError:
# Previous run is probably not completed yet, ignore
# this entry
continue
previous_runs[os.path.join(root, d)] = datetime.datetime.strptime(d, time_format)
break
if success:
# Yes! Success! report any errors until now
if previous_runs:
print("Success after {} failed runs\n".format(len(previous_runs)))
print_runs(previous_runs.keys())
try:
shutil.rmtree(libdir) shutil.rmtree(libdir)
return 0 except FileNotFoundError:
pass
return 0
# Failure # Failure
if previous_runs: if previous_runs:
@ -232,7 +260,8 @@ def main():
print("Cronjob failed\n") print("Cronjob failed\n")
print_runs([libdir], clean=False) print_runs([libdir], clean=False)
release_lock(lckfile) if has_lock:
release_lock(lckfile)
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(main()) sys.exit(main())

View File

@ -5,7 +5,7 @@ with open('README.md', 'r') as fh:
setuptools.setup( setuptools.setup(
name='cronwrapper', name='cronwrapper',
version='0.1.0', version='0.1.5',
author='Fredrik Eriksson', author='Fredrik Eriksson',
author_email='feffe@fulh.ax', author_email='feffe@fulh.ax',
description='A small wrapper to handle cronjob failures', description='A small wrapper to handle cronjob failures',