diff options
-rwxr-xr-x | src/conf-mode/vyatta-update-crontab.py | 236 |
1 files changed, 102 insertions, 134 deletions
diff --git a/src/conf-mode/vyatta-update-crontab.py b/src/conf-mode/vyatta-update-crontab.py index 381221bfb..d94235f24 100755 --- a/src/conf-mode/vyatta-update-crontab.py +++ b/src/conf-mode/vyatta-update-crontab.py @@ -1,17 +1,14 @@ #!/usr/bin/env python3 # -# -# Maintainer: Daniil Baturin <daniil@baturin.org> -# -# Copyright (C) 2013 SO3Group +# Copyright (C) 2017 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as +# it under the terms of the GNU General Public License version 2 or later as # published by the Free Software Foundation. # # 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 +# 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 @@ -19,142 +16,113 @@ # # -#!/usr/bin/env python3 import io import re import sys -sys.path.append("/usr/lib/python3/dist-packages/vyos/") - -from config import VyOSError, Config - - -class CronTask(Config): - def __init__(self, task): - - self.task = task - self.minutes = "*" - self.hours = "*" - self.days = "*" - self.user = "root" - self.executable = None - self.arguments = "" - self.interval = None - self.crontab_spec = None - self._cli_shell_api = "/bin/cli-shell-api" - - # Unused now - self.months = "*" - self.days_of_week = "*" - super(CronTask, self).set_level("system task-scheduler task") - try: - self.user = super(CronTask, self).return_value(" ".join([self.task, "user"])) - except VyOSError: - pass - - try: - byte_executable = super(CronTask, self).return_value(" ".join([self.task, "executable path"])) - self.executable = byte_executable.decode("utf-8") - except VyOSError: - raise VyOSError (task + "must define executable") - - try: - byte_arguments = super(CronTask, self).return_value(" ".join([self.task, "executable arguments"])) - self.executable = byte_arguments.decode("utf-8") - except VyOSError: - pass - - try: - self.interval = super(CronTask, self).return_value(" ".join([self.task, "interval"])) - except VyOSError: - self.interval = None - - try: - byte_crontab_spec = super(CronTask, self).return_value(" ".join([self.task, "crontab-spec"])) - self.crontab_spec = byte_crontab_spec - except: - self.crontab_spec = None +from vyos.config import VyOSError, Config + + +crontab_file = "/etc/cron.d/vyos-crontab" + + +def format_task(minute="*", hour="*", day="*", dayofweek="*", month="*", user="root", rawspec=None, command=""): + fmt_full = "{minute} {hour} {day} {month} {dayofweek} {user} {command}\n" + fmt_raw = "{spec} {user} {command}\n" + + if rawspec is None: + s = fmt_full.format(minute=minute, hour=hour, day=day, + dayofweek=dayofweek, month=month, command=command, user=user) + else: + s = fmt_raw.format(spec=rawspec, user=user, command=command) + + return s + +def split_interval(s): + result = re.search(r"(\d+)([mdh]?)", s) + value = int(result.group(1)) + suffix = result.group(2) + return( (value, suffix) ) + +def make_command(executable, arguments): + if arguments: + return("{0} {1}".format(executable, arguments)) + else: + return(executable) def get_config(): conf = Config() conf.set_level("system task-scheduler task") - tasks = conf.list_nodes("") - list_of_instanses=[] + task_names = conf.list_nodes("") + tasks = [] + + for name in task_names: + interval = conf.return_value("{0} interval".format(name)) + spec = conf.return_value("{0} crontab-spec".format(name)) + executable = conf.return_value("{0} executable path".format(name)) + args = conf.return_value("{0} executable arguments".format(name)) + task = { + "name": name, + "interval": interval, + "spec": spec, + "executable": executable, + "args": args + } + tasks.append(task) + + return tasks + +def verify(tasks): for task in tasks: - list_of_instanses.append(CronTask(task.decode("utf-8"))) - return list_of_instanses - - -def verify(config): - for task in config: - if task.interval and task.crontab_spec: - raise VyOSError(task, "can not use interval and crontab-spec at the same time!") - - if task.interval: - result = re.search(b"(\d+)([mdh]?)", task.interval) - value = int(result.group(1)) - suffix = result.group(2) - - - if not suffix or suffix == b"m": - if value > 60: - raise VyOSError("Interval in minutes must not exceed 60!") - task.minutes = "*/" + str(value) - - elif suffix == b"h": - if value > 24: - raise VyOSError("Interval in hours must not exceed 24!") - task.minutes = "0" - task.hours = "*/" + str(value) - - elif suffix == b"d": - if value > 31: - raise VyOSError("Interval in days must not exceed 31!") - - task.minutes = "0" - task.hours = "0" - task.days = "*/" + str(value) - elif task.interval and task.crontab_spec: - raise VyOSError(task, "must define either interval or crontab-spec") - return None - - -def generate(config): - crontab = "/etc/cron.d/vyatta-crontab" - crontab_header = "### Added by /opt/vyatta/sbin/vyatta-update-crontab.py ###\n" - crontab_append = crontab_header - count = 0 - for task in config: - if task.interval: - crontab_string = "{minutes} {hours} {days} {months} {days_of_week} {user} {executable} {arguments}\n".format( - minutes=task.minutes, - hours=task.hours, - days=task.days, - months=task.months, - days_of_week=task.days_of_week, - user=task.user, - executable=task.executable, - arguments=task.arguments - ) - elif task.crontab_spec: - crontab_string = "{crontab_spec) {user} {executable} {arguments}\n".format( - crontab_spec=task.crontab_spec, - user=task.user, - executable=task.executable, - arguments=task.arguments - ) - crontab_append = crontab_append + crontab_string - count = count + 1 - if count > 0: - try: - f = io.open(crontab, "w") - f.write(crontab_append) - f.close() - except IOError: - print("Could not open /etc/crontab for write") - + if not task["interval"] and not task["spec"]: + raise VyOSError(task, "Invalid task {0}: must define either interval or crontab-spec".format(task["name"])) + + if task["interval"]: + if task["spec"]: + raise VyOSError("Invalid task {0}: cannot use interval and crontab-spec at the same time".format(task["name"])) + + if not re.match(r"^\d+[mdh]?$", task["interval"]): + raise(VyOSError("Invalid interval {0} in task {1}: interval should be a number optionally followed by m, h, or d".format(task["name"], task["interval"]))) + else: + # Check if values are within allowed range + value, suffix = split_interval(task["interval"]) + + if not suffix or suffix == "m": + if value > 60: + raise VyOSError("Invalid task {0}: interval in minutes must not exceed 60".format(task["name"])) + elif suffix == "h": + if value > 24: + raise VyOSError("Invalid task {0}: interval in hours must not exceed 24".format(task["name"])) + elif suffix == "d": + if value > 31: + raise VyOSError("Invalid task {0}: interval in days must not exceed 31".format(task["name"])) + +def generate(tasks): + crontab_header = "### Generated by vyos-update-crontab.py ###\n" + if len(tasks) == 0: + os.remove(crontab_file) + else: + crontab_lines = [] + for task in tasks: + command = make_command(task["executable"], task["args"]) + if task["spec"]: + line = format_task(command=command, rawspec=task["spec"]) + else: + value, suffix = split_interval(task["interval"]) + if not suffix or suffix == "m": + line = format_task(command=command, minute="*/{0}".format(value)) + elif suffix == "h": + line = format_task(command=command, minute="0", hour="*/{0}".format(value)) + elif suffix == "d": + line = format_task(command=command, minute="0", hour="0", day="*/{0}".format(value)) + crontab_lines.append(line) + + with open(crontab_file, 'w') as f: + f.write(crontab_header) + f.writelines(crontab_lines) def apply(config): + # No daemon restarts etc. needed for cron pass @@ -164,6 +132,6 @@ if __name__ == '__main__': verify(c) generate(c) apply(c) - except VyOSError: - sys.exit(0) - + except VyOSError as e: + print(e) + sys.exit(1) |