#!/usr/bin/env python # -*- coding: utf-8 -*- """ utilitaire de lancement en fonction - cron - bareos """ import sys import time from os import readlink, unlink from os.path import join from glob import glob from pyeole.process import system_out from pyeole.schedule import SCHEDULE_DIR from pyeole.bareos import is_running_jobs, bareos_get_jobs_list from creole.client import CreoleClient from pyeole.i18n import i18n from pyeole.log import init_logging _ = i18n('eole-schedule') log = init_logging(name=u'eole-schedule', level='info', syslog=True, console=['stdout', 'stderr']) client = CreoleClient() NOW = time.strftime('%d/%m/%y %H:%M', time.localtime()) # day in month MONTH_DAY = int(time.strftime('%d', time.localtime())) # day in week WEEK_DAY = int(time.strftime('%w', time.localtime())) HOUR = int(time.strftime('%H', time.localtime())) # night start at 12 if HOUR > 12: WEEK_DAY += 1 if WEEK_DAY == 0: # sunday is 7 WEEK_DAY = 7 if WEEK_DAY == 8: WEEK_DAY = 1 def log_parts(func): def split(msg): shreds = msg.split('\n') return [func(shred) for shred in shreds if len(shred) > 0] return split log.info = log_parts(log.info) log.error = log_parts(log.error) log.warning = log_parts(log.warning) def run_runparts(mode, bareos_type): """ run part script test if weekly or monthly script must be launched this day """ if mode == 'weekly' and WEEK_DAY != client.get('/schedule/schedule/weekday'): return if mode == 'monthly' and ( WEEK_DAY != client.get('/schedule/schedule/monthday') or MONTH_DAY > 7 ): return part_str = u"{} schedule {}".format(bareos_type, mode) log.info(_("Starting {}").format(part_str)) dirname = join(SCHEDULE_DIR, mode, bareos_type) env = {'PATH': '/sbin:/usr/sbin:/bin:/usr/bin:/usr/share/eole', 'LC_ALL': 'fr_FR.UTF-8'} if mode != 'once': runparts_cmd = "/bin/run-parts --exit-on-error --report {} --arg {}" wrapped_runparts_cmd = ['/bin/bash', '-c', runparts_cmd.format(dirname, mode)] ret, out, err = system_out(wrapped_runparts_cmd, env=env) else: # unlink script before launch it # (for example remove 'reboot' link before restart the machine) names = glob(join(dirname, '*')) names.sort() ret = 0 out = None err = None for name in names: script = readlink(name) unlink(name) wrapped_runparts_cmd = ['/bin/bash', '-c', script] ret, out, err = system_out(wrapped_runparts_cmd, env=env) if ret != 0: break if out: log.info(out) if err: log.error(err) if ret != 0: # on affiche sur stderr pour que cron le récupère et le mail # ce qui est printé sur stdout est envoyé dans les logs if out: sys.stderr.write(out) if err: sys.stderr.write(err) sys.stderr.write(_("Error detected\n")) log.error(_("{} exited with error return code").format(part_str)) sys.exit(ret) else: log.info(_("{} finished").format(part_str)) def schedule_pre(): run_runparts('daily', 'pre') run_runparts('weekly', 'pre') run_runparts('monthly', 'pre') run_runparts('once', 'pre') def schedule_post(): i = 0 while is_running_jobs(): time.sleep(1) i += 1 if i == 30: log.info(_("Job already running, cancelling")) sys.exit(1) run_runparts('daily', 'post') run_runparts('weekly', 'post') run_runparts('monthly', 'post') run_runparts('once', 'post') def schedule_cron(): """ If schedule.py is launched by cron, try to run pre and post cron file for daily, weekly and monthly if no backup is set this day """ def exit_not_cron(): log.info(_("bareos is set for this day, cancelled")) sys.exit(0) try: bareosjobs = bareos_get_jobs_list() for job in bareosjobs: day = int(job['day']) if job['job'] == 'daily': if day <= WEEK_DAY <= job['end_day']: exit_not_cron() elif job['job'] == 'weekly': if WEEK_DAY == day: exit_not_cron() elif job['job'] == 'monthly': if WEEK_DAY == day and MONTH_DAY < 8: exit_not_cron() else: raise Exception(_('Unknown job: {0}').format(job['job'])) except SystemExit: raise except: pass run_runparts('daily', 'pre') run_runparts('daily', 'post') run_runparts('weekly', 'pre') run_runparts('weekly', 'post') run_runparts('monthly', 'pre') run_runparts('monthly', 'post') run_runparts('once', 'pre') run_runparts('once', 'post') # __________________________________________________ if __name__ == '__main__': usage = """usage: {0} bareos [pre|post] {0} cron""".format(sys.argv[0]) if len(sys.argv) == 1: print usage sys.exit(1) if len(sys.argv) > 3: log.error(_("Too many arguments: {0}").format(sys.argv)) print usage sys.exit(1) mode = sys.argv[1] if mode == 'bareos': # pre|post if len(sys.argv) == 2: log.error(_("Not enough arguments: {0}").format(sys.argv)) print usage sys.exit(1) if sys.argv[2] not in ['pre', 'post']: log.error(_("Second argument must be pre or post: {0}").format(sys.argv)) print usage sys.exit(1) bareos_type = sys.argv[2] if bareos_type == 'pre': schedule_pre() elif bareos_type == 'post': schedule_post() elif mode == 'cron': if len(sys.argv) != 2: log.error(_("Too many arguments for cron: {0}").format(sys.argv)) print usage sys.exit(1) schedule_cron() else: log.error(_("Unknown schedule type : {0}").format(mode)) print usage sys.exit(1)