""" Telltale files helpers """ import argparse import datetime import logging import os import sys from mylib import pretty_format_timedelta from mylib.scripts.helpers import get_opts_parser, init_logging log = logging.getLogger(__name__) DEFAULT_WARNING_THRESHOLD = 90 DEFAULT_CRITICAL_THRESHOLD = 240 class TelltaleFile: """Telltale file helper class""" def __init__(self, filepath=None, filename=None, dirpath=None): assert filepath or filename, "filename or filepath is required" if filepath: assert ( not filename or os.path.basename(filepath) == filename ), "filepath and filename does not match" assert ( not dirpath or os.path.dirname(filepath) == dirpath ), "filepath and dirpath does not match" self.filename = filename if filename else os.path.basename(filepath) self.dirpath = ( dirpath if dirpath else (os.path.dirname(filepath) if filepath else os.getcwd()) ) self.filepath = filepath if filepath else os.path.join(self.dirpath, self.filename) @property def last_update(self): """Retrieve last update datetime of the telltall file""" try: return datetime.datetime.fromtimestamp(os.stat(self.filepath).st_mtime) except FileNotFoundError: log.info("Telltale file not found (%s)", self.filepath) return None def update(self): """Update the telltale file""" log.info("Update telltale file (%s)", self.filepath) try: os.utime(self.filepath, None) except FileNotFoundError: # pylint: disable=consider-using-with open(self.filepath, "a", encoding="utf-8").close() def remove(self): """Remove the telltale file""" try: os.remove(self.filepath) return True except FileNotFoundError: return True @classmethod def check_entrypoint( cls, argv=None, description=None, default_filepath=None, default_warning_threshold=None, default_critical_threshold=None, fail_message=None, success_message=None, ): """Entry point of the script to check a telltale file last update""" argv = argv if argv else sys.argv description = description if description else "Check last execution date" parser = get_opts_parser(desc=description, exit_on_error=False) parser.add_argument( "-p", "--telltale-file-path", action="store", type=str, dest="telltale_file_path", help=f"Telltale file path (default: {default_filepath})", default=default_filepath, required=not default_filepath, ) default_warning_threshold = ( default_warning_threshold if default_warning_threshold is not None else DEFAULT_WARNING_THRESHOLD ) default_critical_threshold = ( default_critical_threshold if default_critical_threshold is not None else DEFAULT_CRITICAL_THRESHOLD ) parser.add_argument( "-w", "--warning", type=int, dest="warning", help=( "Specify warning threshold (in minutes, default: " f"{default_warning_threshold} minutes)" ), default=default_warning_threshold, ) parser.add_argument( "-c", "--critical", type=int, dest="critical", help=( "Specify critical threshold (in minutes, default: " f"{default_critical_threshold} minutes)" ), default=default_critical_threshold, ) try: options = parser.parse_args(argv[1:]) except argparse.ArgumentError as err: print(f"UNKNOWN - {err}") sys.exit(3) # Initialize logs init_logging(options, argv[0]) telltale_file = cls(filepath=options.telltale_file_path) last = telltale_file.last_update if not last: status = "UNKNOWN" exit_code = 3 msg = ( fail_message if fail_message else "Fail to retrieve last successful date of execution" ) else: delay = datetime.datetime.now() - last msg = ( success_message if success_message else "Last successful execution was {last_delay} ago ({last_date})" ).format( last_delay=pretty_format_timedelta(delay), last_date=last.strftime("%Y/%m/%d %H:%M:%S"), ) if delay >= datetime.timedelta(minutes=options.critical): status = "CRITICAL" exit_code = 2 elif delay >= datetime.timedelta(minutes=options.warning): status = "WARNING" exit_code = 1 else: status = "OK" exit_code = 0 print(f"{status} - {msg}") sys.exit(exit_code)