fix(crontab): fully validate the complete crontab syntax
This commit is contained in:
parent
f27cd047e1
commit
0b573b7e15
3 changed files with 33 additions and 2 deletions
|
@ -17,7 +17,7 @@ RESTIC_KEEP_MONTHLY=12
|
||||||
RESTIC_KEEP_YEARLY=3
|
RESTIC_KEEP_YEARLY=3
|
||||||
|
|
||||||
LOG_LEVEL=info
|
LOG_LEVEL=info
|
||||||
CRON_SCHEDULE=10 2 * * *
|
CRON_SCHEDULE=10 2-4 */4 1,2,*/3 *
|
||||||
|
|
||||||
# EMAIL_HOST=
|
# EMAIL_HOST=
|
||||||
# EMAIL_PORT=
|
# EMAIL_PORT=
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# ┌───────────── minute (0 - 59)
|
# ┌───────────── minute (0 - 59)
|
||||||
# │ ┌───────────── hour (0 - 23)
|
# │ ┌───────────── hour (0 - 23)
|
||||||
|
@ -30,16 +34,23 @@ def generate_crontab(config):
|
||||||
|
|
||||||
def validate_schedule(schedule: str):
|
def validate_schedule(schedule: str):
|
||||||
"""Validate crontab format"""
|
"""Validate crontab format"""
|
||||||
|
logger.debug(f"validating crontab schedule {schedule}")
|
||||||
parts = schedule.split()
|
parts = schedule.split()
|
||||||
if len(parts) != 5:
|
if len(parts) != 5:
|
||||||
|
logger.debug(f"crontab has only {len(parts)}/5 parts")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
minute, hour, day, month, weekday = parts
|
minute, hour, day, month, weekday = parts
|
||||||
try:
|
try:
|
||||||
|
logger.debug(f"[crontab] validating minute: {minute}")
|
||||||
validate_field(minute, 0, 59)
|
validate_field(minute, 0, 59)
|
||||||
|
logger.debug(f"[crontab] validating hour: {hour}")
|
||||||
validate_field(hour, 0, 23)
|
validate_field(hour, 0, 23)
|
||||||
|
logger.debug(f"[crontab] validating day: {day}")
|
||||||
validate_field(day, 1, 31)
|
validate_field(day, 1, 31)
|
||||||
|
logger.debug(f"[crontab] validating month: {month}")
|
||||||
validate_field(month, 1, 12)
|
validate_field(month, 1, 12)
|
||||||
|
logger.debug(f"[crontab] validating weekday: {weekday}")
|
||||||
validate_field(weekday, 0, 6)
|
validate_field(weekday, 0, 6)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return False
|
return False
|
||||||
|
@ -49,8 +60,28 @@ def validate_schedule(schedule: str):
|
||||||
|
|
||||||
def validate_field(value, min, max):
|
def validate_field(value, min, max):
|
||||||
if value == '*':
|
if value == '*':
|
||||||
|
logger.debug("[crontab] validation success: *")
|
||||||
return
|
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)
|
i = int(value)
|
||||||
return min <= i <= max
|
return min <= i <= max
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue