def ScheduleSystemCronJobs(names=None): """Schedules all system cron jobs.""" errors = [] disabled_classes = config.CONFIG["Cron.disabled_cron_jobs"] for name in disabled_classes: try: SystemCronJobRegistry.CronJobClassByName(name) except ValueError: errors.append("Cron job not found: %s." % name) continue if names is None: names = SystemCronJobRegistry.SYSTEM_CRON_REGISTRY.keys() for name in names: cls = SystemCronJobRegistry.CronJobClassByName(name) enabled = cls.enabled and name not in disabled_classes system = rdf_cronjobs.CronJobAction.ActionType.SYSTEM_CRON_ACTION args = rdf_cronjobs.CronJobAction( action_type=system, system_cron_action=rdf_cronjobs.SystemCronAction(job_class_name=name)) job = rdf_cronjobs.CronJob( cron_job_id=name, args=args, enabled=enabled, frequency=cls.frequency, lifetime=cls.lifetime, allow_overruns=cls.allow_overruns) data_store.REL_DB.WriteCronJob(job) if errors: raise ValueError("Error(s) while parsing Cron.disabled_cron_jobs: %s" % errors)
def RunJob(self, job): """Does the actual work of the Cron, if the job is due to run. Args: job: The cronjob rdfvalue that should be run. Must be leased. Returns: A boolean indicating if this cron job was started or not. False may be returned when the threadpool is already full. Raises: LockError: if the object is not locked. ValueError: If the job argument is invalid. """ if not job.leased_until: raise LockError("CronJob must be leased for Run() to be called.") if job.leased_until < rdfvalue.RDFDatetime.Now(): raise LockError("CronJob lease expired for %s." % job.cron_job_id) logging.info("Starting cron job: %s", job.cron_job_id) if job.args.action_type == job.args.ActionType.SYSTEM_CRON_ACTION: cls_name = job.args.system_cron_action.job_class_name job_cls = SystemCronJobRegistry.CronJobClassByName(cls_name) name = "%s runner" % cls_name elif job.args.action_type == job.args.ActionType.HUNT_CRON_ACTION: job_cls = CronJobRegistry.CronJobClassByName("RunHunt") name = "Hunt runner" else: raise ValueError("CronJob %s doesn't have a valid args type set." % job.cron_job_id) run_state = rdf_cronjobs.CronJobRun( cron_job_id=job.cron_job_id, status="RUNNING") run_state.GenerateRunId() run_obj = job_cls(run_state, job) wait_for_start_event, signal_event, wait_for_write_event = ( threading.Event(), threading.Event(), threading.Event()) try: self._GetThreadPool().AddTask( target=run_obj.StartRun, args=(wait_for_start_event, signal_event, wait_for_write_event), name=name, blocking=False, inline=False) if not wait_for_start_event.wait(TASK_STARTUP_WAIT): logging.error("Cron job run task for %s is too slow to start.", job.cron_job_id) # Most likely the thread pool is full and the task is sitting on the # queue. Make sure we don't put more things on the queue by returning # False. return False # We know that the cron job task has started, unblock it by setting # the signal event. If signal_event is not set (this happens if the # task sits on a ThreadPool's queue doing nothing, see the # if-statement above) the task will just be a no-op when ThreadPool # finally gets to it. This way we can ensure that we can safely return # the lease and let another worker schedule the same job. signal_event.set() wait_for_write_event.wait(TASK_STARTUP_WAIT) return True except threadpool.Full: return False