def StopCurrentRun(self, reason="Cron lifetime exceeded.", force=True): current_flow_urn = self.Get(self.Schema.CURRENT_FLOW_URN) if current_flow_urn: flow.GRRFlow.TerminateFlow( current_flow_urn, reason=reason, force=force, token=self.token) self.Set( self.Schema.LAST_RUN_STATUS, rdf_cronjobs.CronJobRunStatus( status=rdf_cronjobs.CronJobRunStatus.Status.TIMEOUT)) self.DeleteAttribute(self.Schema.CURRENT_FLOW_URN) self.Flush()
def testInitFromAff4Object(self): state = rdf_protodict.AttributedDict() state["quux"] = "norf" state["thud"] = "blargh" with aff4.FACTORY.Create("aff4:/cron/foo", aff4_type=cronjobs.CronJob, mode="w", token=self.token) as fd: args = rdf_cronjobs.CreateCronJobFlowArgs() args.periodicity = rdfvalue.Duration("1d") args.lifetime = rdfvalue.Duration("30d") args.description = "testdescription" status = rdf_cronjobs.CronJobRunStatus(status="OK") fd.Set(fd.Schema.CURRENT_FLOW_URN, rdfvalue.RDFURN("aff4:/flow/bar")) fd.Set(fd.Schema.CRON_ARGS, args) fd.Set(fd.Schema.LAST_RUN_TIME, self._DATETIME("2001-01-01")) fd.Set(fd.Schema.LAST_RUN_STATUS, status) fd.Set(fd.Schema.DISABLED, rdfvalue.RDFBool(True)) fd.Set(fd.Schema.STATE_DICT, state) with aff4.FACTORY.Open("aff4:/cron/foo", mode="r", token=self.token) as fd: api_cron_job = cron_plugin.ApiCronJob().InitFromAff4Object(fd) self.assertEqual(api_cron_job.cron_job_id, "foo") self.assertEqual(api_cron_job.current_run_id, "bar") self.assertEqual(api_cron_job.description, "testdescription") self.assertEqual(api_cron_job.last_run_time, self._DATETIME("2001-01-01")) self.assertEqual(api_cron_job.last_run_status, "FINISHED") self.assertEqual(api_cron_job.frequency, rdfvalue.Duration("1d")) self.assertEqual(api_cron_job.lifetime, rdfvalue.Duration("30d")) self.assertFalse(api_cron_job.enabled) api_state_items = {_.key: _.value for _ in api_cron_job.state.items} self.assertEqual(api_state_items, {"quux": "norf", "thud": "blargh"})
def Run(self, force=False): """Do the actual work of the Cron. Will first check if DueToRun is True. CronJob object must be locked (i.e. opened via OpenWithLock) for Run() to be called. Args: force: If True, the job will run no matter what (i.e. even if DueToRun() returns False). Raises: LockError: if the object is not locked. """ if not self.locked: raise aff4.LockError("CronJob must be locked for Run() to be called.") self.KillOldFlows() # If currently running flow has finished, update our state. current_flow_urn = self.Get(self.Schema.CURRENT_FLOW_URN) if current_flow_urn: current_flow = aff4.FACTORY.Open(current_flow_urn, token=self.token) runner = current_flow.GetRunner() if not runner.IsRunning(): if runner.context.state == rdf_flow_runner.FlowContext.State.ERROR: self.Set( self.Schema.LAST_RUN_STATUS, rdf_cronjobs.CronJobRunStatus( status=rdf_cronjobs.CronJobRunStatus.Status.ERROR)) stats.STATS.IncrementCounter( "cron_job_failure", fields=[self.urn.Basename()]) else: self.Set( self.Schema.LAST_RUN_STATUS, rdf_cronjobs.CronJobRunStatus( status=rdf_cronjobs.CronJobRunStatus.Status.OK)) start_time = self.Get(self.Schema.LAST_RUN_TIME) elapsed = time.time() - start_time.AsSecondsSinceEpoch() stats.STATS.RecordEvent( "cron_job_latency", elapsed, fields=[self.urn.Basename()]) self.DeleteAttribute(self.Schema.CURRENT_FLOW_URN) self.Flush() if not force and not self.DueToRun(): return # Make sure the flow is created with cron job as a parent folder. cron_args = self.Get(self.Schema.CRON_ARGS) cron_args.flow_runner_args.base_session_id = self.urn flow_urn = flow.StartFlow( runner_args=cron_args.flow_runner_args, args=cron_args.flow_args, token=self.token, sync=False) self.Set(self.Schema.CURRENT_FLOW_URN, flow_urn) self.Set(self.Schema.LAST_RUN_TIME, rdfvalue.RDFDatetime.Now()) self.Flush()