diff --git a/restic_compose_backup.env b/restic_compose_backup.env index 8f07544..d0ad1ee 100644 --- a/restic_compose_backup.env +++ b/restic_compose_backup.env @@ -17,7 +17,7 @@ RESTIC_KEEP_MONTHLY=12 RESTIC_KEEP_YEARLY=3 LOG_LEVEL=info -CRON_SCHEDULE=10 2 * * * +CRON_SCHEDULE=10 2-4 */4 1,2,*/3 * # EMAIL_HOST= # EMAIL_PORT= diff --git a/src/crontab b/src/crontab index 23ddd03..2f22701 100644 --- a/src/crontab +++ b/src/crontab @@ -1,2 +1,2 @@ -10 2 * * * source /env.sh && rcb backup > /proc/1/fd/1 +10 2-4 */4 1,2,*/3 * source /env.sh && rcb backup > /proc/1/fd/1 diff --git a/src/restic_compose_backup/cron.py b/src/restic_compose_backup/cron.py index 4eb7c0c..f67470e 100644 --- a/src/restic_compose_backup/cron.py +++ b/src/restic_compose_backup/cron.py @@ -1,3 +1,7 @@ +import logging + +logger = logging.getLogger(__name__) + """ # ┌───────────── minute (0 - 59) # │ ┌───────────── hour (0 - 23) @@ -30,16 +34,23 @@ def generate_crontab(config): def validate_schedule(schedule: str): """Validate crontab format""" + logger.debug(f"validating crontab schedule {schedule}") parts = schedule.split() if len(parts) != 5: + logger.debug(f"crontab has only {len(parts)}/5 parts") return False minute, hour, day, month, weekday = parts try: + logger.debug(f"[crontab] validating minute: {minute}") validate_field(minute, 0, 59) + logger.debug(f"[crontab] validating hour: {hour}") validate_field(hour, 0, 23) + logger.debug(f"[crontab] validating day: {day}") validate_field(day, 1, 31) + logger.debug(f"[crontab] validating month: {month}") validate_field(month, 1, 12) + logger.debug(f"[crontab] validating weekday: {weekday}") validate_field(weekday, 0, 6) except ValueError: return False @@ -49,8 +60,28 @@ def validate_schedule(schedule: str): def validate_field(value, min, max): if value == '*': + logger.debug("[crontab] validation success: *") return + elif "," in value: + items = value.split(",") + logger.debug(f"[crontab] recursive validation of {items}") + return all(validate_field(val, min, max) for val in items) + elif "*/" in value: + logger.debug(f"[crontab] validating */ pattern") + i = int(value.split("/")[1]) + logger.debug(f"[crontab] got {i} from {value}") + return min <= i <= max + elif "-" in value: + logger.debug("[crontab] validating range") + split = value.split("-") + if len(split) < 2: + logger.debug(f"[crontab] validation error: {value} has has a one sided range") + return False + minVal = int(split[0]) + maxVal = int(split[1]) + return (min <= minVal <= maxVal) and (minVal <= maxVal <= max) + logger.debug(f"[crontab] validating simple number {value}") i = int(value) return min <= i <= max