Created
November 28, 2013 09:39
-
-
Save georgepsarakis/7689438 to your computer and use it in GitHub Desktop.
Crontab file syntax check
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
import argparse | |
import os | |
import re | |
''' | |
**** Crontab file syntax checking *** | |
Useful for scripts stored under /etc/cron.d | |
and for automating crontab task distribution | |
''' | |
class FileNotFoundException(Exception): pass | |
class ParseErrorException(Exception): pass | |
class UnknownPredefinedKeywordException(Exception): pass | |
class UnknownTimeEntryException(Exception): pass | |
class NoUserFoundException(Exception): pass | |
class InvalidStateException(Exception): pass | |
PREDEFINED = [ 'yearly', 'annually', 'monthly', | |
'weekly', 'daily', 'hourly', 'reboot' ] | |
R_comment = re.compile(r'^#') | |
R_predefined_keywords = re.compile(r'^@') | |
R_interval = re.compile(r'\*\/[0-9]+') | |
R_once_every = re.compile(r'[0-9]+') | |
R_always = re.compile(r'\*') | |
R_user = re.compile(r'^[a-z0-9_]+') | |
def is_none(v): | |
return v is None | |
def read_file(parameters): | |
if not os.path.exists(parameters.file): | |
raise Exception('File not found') | |
cron_file = [] | |
with open(parameters.file, 'r') as f: | |
cron_file = [ line.strip() for line in f.readlines() ] | |
return cron_file | |
def check_time_entry(entry): | |
if not is_none(R_always.match(entry)): | |
return 'always' | |
elif not is_none(R_once_every.match(entry)): | |
return 'once' | |
elif not is_none(R_interval.match(entry)): | |
return 'interval' | |
elif not is_none(R_user.match(entry)): | |
return 'user' | |
return None | |
def parse_file(parameters): | |
cron_file = read_file(parameters) | |
with_user = parameters.user | |
for linenum, line in enumerate(cron_file): | |
linenum += 1 | |
''' skip commented and empty lines ''' | |
if line.strip() == "" or not is_none(R_comment.match(line)): | |
continue | |
if not is_none(R_predefined_keywords.match(line)): | |
if not line.split()[0].strip('@') in PREDEFINED: | |
raise UnknownPredefinedKeywordException('Line %d' % linenum) | |
return False | |
if with_user: | |
parameters = 6 | |
else: | |
parameters = 5 | |
time_entries = [] | |
for status in [ check_time_entry(entry) for entry in line.split()[:parameters] ]: | |
if is_none(status): | |
raise UnknownTimeEntryException('Line %d' % linenum) | |
time_entries.append(status) | |
for position, state in enumerate(time_entries[:-1]): | |
if not state in [ "once", "always", "interval" ]: | |
raise InvalidStateException('Line %d, Entry %d' % (linenum, position + 1)) | |
if with_user: | |
if time_entries[-1] != 'user': | |
raise NoUserFoundException('Line %d' % linenum) | |
return True | |
if __name__ == "__main__": | |
argparser = argparse.ArgumentParser('Cron file syntax check') | |
argparser.add_argument('-f', '--file', help='File to check.', required=True) | |
argparser.add_argument('-u', '--user', help='Add user in syntax (for scripts in /etc/cron.d).', required=False, default=False, action='store_true') | |
parameters = argparser.parse_args() | |
if parse_file(parameters): | |
print 'ok' | |
else: | |
print 'error' | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, nice script .... but I tested the script with the following file, and it didnt throw an error (the first line is wrong it is missing one *
crontab for process2
05 * * * process2-staging --date=
date +"\%Y\%m" --date="1 sec ago"
06 * * * * process2-staging --date=
date +"\%Y\%m\%d" --date="1 sec ago"