Exemple #1
0
if __name__ == '__main__':
    # Force no log init since we use separate logger
    configuration = get_configuration_object(skip_log=True)

    log_level = configuration.loglevel
    if sys.argv[1:] and sys.argv[1] in ['debug', 'info', 'warning', 'error']:
        log_level = sys.argv[1]

    # Use separate logger
    logger = daemon_logger("monitor", configuration.user_monitor_log,
                           log_level)
    configuration.logger = logger

    # Allow e.g. logrotate to force log re-open after rotates
    register_hangup_handler(configuration)

    if not configuration.site_enable_jobs:
        err_msg = "Job support is disabled in configuration!"
        logger.error(err_msg)
        print(err_msg)
        sys.exit(1)

    print("""
Running grid monitor generator.

Set the MIG_CONF environment to the server configuration path
unless it is available in mig/server/MiGserver.conf
""")

    # Make sure that the default VGrid home used by monitor exists
Exemple #2
0
def monitor(configuration):
    """Monitors the filesystem for crontab changes"""

    pid = multiprocessing.current_process().pid

    print('Starting global crontab monitor process')
    logger.info('Starting global crontab monitor process')

    # Set base_dir and base_dir_len

    shared_state['base_dir'] = os.path.join(configuration.user_settings)
    shared_state['base_dir_len'] = len(shared_state['base_dir'])

    # Allow e.g. logrotate to force log re-open after rotates
    register_hangup_handler(configuration)

    # Monitor crontab configurations

    crontab_monitor_home = shared_state['base_dir']
    recursive_crontab_monitor = True

    crontab_monitor = Observer()
    crontab_pattern = os.path.join(crontab_monitor_home, '*', crontab_name)
    atjobs_pattern = os.path.join(crontab_monitor_home, '*', atjobs_name)
    shared_state['crontab_handler'] = MiGCrontabEventHandler(
        patterns=[crontab_pattern, atjobs_pattern], ignore_directories=False,
        case_sensitive=True)

    crontab_monitor.schedule(shared_state['crontab_handler'],
                             configuration.user_settings,
                             recursive=recursive_crontab_monitor)
    crontab_monitor.start()

    if len(crontab_monitor._emitters) != 1:
        logger.error('(%s) Number of crontab_monitor._emitters != 1' % pid)
        return 1
    crontab_monitor_emitter = min(crontab_monitor._emitters)
    if not hasattr(crontab_monitor_emitter, '_inotify'):
        logger.error('(%s) crontab_monitor_emitter require inotify' % pid)
        return 1
    shared_state['crontab_inotify'] = crontab_monitor_emitter._inotify._inotify

    logger.info('(%s) trigger crontab and atjobs refresh' % (pid, ))

    # Fake touch event on all crontab files to load initial crontabs

    # logger.info('(%s) trigger load on all files (greedy) matching %s or %s' \
    #            % (pid, crontab_pattern, atjobs_pattern))

    # We manually walk and test to get the greedy "*" directory match behaviour
    # of the PatternMatchingEventHandler

    all_crontab_files, all_atjobs_files = [], []

    for (root, _, files) in walk(crontab_monitor_home):
        if crontab_name in files:
            crontab_path = os.path.join(root, crontab_name)
            all_crontab_files.append(crontab_path)
        if atjobs_name in files:
            atjobs_path = os.path.join(root, atjobs_name)
            all_atjobs_files.append(atjobs_path)

    for target_path in all_crontab_files + all_atjobs_files:

        logger.debug('(%s) trigger load on cron/at file in %s' %
                     (pid, target_path))

        shared_state['crontab_handler'].dispatch(
            FileModifiedEvent(target_path))

    # logger.debug('(%s) loaded initial crontabs:\n%s' % (pid,
    # all_crontab_files))

    while not stop_running.is_set():
        try:
            loop_start = datetime.datetime.now()
            loop_minute = loop_start.replace(second=0, microsecond=0)
            logger.debug('main loop started with %d crontabs and %d atjobs' %
                         (len(all_crontabs), len(all_atjobs)))
            for crontab_path, user_crontab in all_crontabs.items():
                client_dir = os.path.basename(os.path.dirname(crontab_path))
                client_id = client_dir_id(client_dir)
                for entry in user_crontab:
                    logger.debug('inspect cron entry for %s: %s' %
                                 (client_id, entry))
                    if cron_match(configuration, loop_minute, entry):
                        logger.info('run matching cron entry: %s' % entry)
                        run_handler(configuration, client_id, loop_minute,
                                    entry)
            for atjobs_path, user_atjobs in all_atjobs.items():
                client_dir = os.path.basename(os.path.dirname(atjobs_path))
                client_id = client_dir_id(client_dir)
                remaining = []
                for entry in user_atjobs:
                    logger.debug('inspect atjobs entry for %s: %s' %
                                 (client_id, entry))
                    remain_mins = at_remain(configuration, loop_minute, entry)
                    if remain_mins == 0:
                        logger.info('run matching at entry: %s' % entry)
                        run_handler(configuration, client_id, loop_minute,
                                    entry)
                    elif remain_mins > 0:
                        remaining.append(entry)
                    else:
                        logger.info('removing expired at job: %s' % entry)
                # Update remaining jobs to clean up expired
                if remaining:
                    all_atjobs[atjobs_path] = remaining
                else:
                    del all_atjobs[atjobs_path]
        except KeyboardInterrupt:
            print('(%s) caught interrupt' % pid)
            stop_running.set()
        except Exception as exc:
            logger.error('unexpected exception in monitor: %s' % exc)
            import traceback
            print(traceback.format_exc())

        # Throttle down until next minute

        loop_time = (datetime.datetime.now() - loop_start).seconds
        if loop_time > 60:
            logger.warning('(%s) loop did not finish before next tick: %s' %
                           (os.getpid(), loop_time))
            loop_time = 59
        # Target sleep until start of next minute
        sleep_time = max(60 - (loop_time + loop_start.second), 1)
        # TODO: this debug log never shows up - conflict with user info log?
        #       at least it does if changed to info.
        logger.debug('main loop sleeping %ds' % sleep_time)
        # print('main loop sleeping %ds' % sleep_time)
        time.sleep(sleep_time)

    print('(%s) Exiting crontab monitor' % pid)
    logger.info('(%s) Exiting crontab monitor' % pid)
    return 0