Esempio n. 1
0
    def testCronJobRespectsStartTime(self):
        with test_lib.FakeTime(0):
            cron_manager = aff4_cronjobs.GetCronManager()
            start_time1 = rdfvalue.RDFDatetime(100 * 1000 * 1000)
            cron_args1 = rdf_cronjobs.CreateCronJobFlowArgs(
                start_time=start_time1)
            cron_args1.flow_runner_args.flow_name = "FakeCronJobRel"

            cron_args2 = rdf_cronjobs.CreateCronJobFlowArgs()
            cron_args2.flow_runner_args.flow_name = "FakeCronJobRel"

            cron_job_id1 = cron_manager.CreateJob(cron_args1)
            cron_job_id2 = cron_manager.CreateJob(cron_args2)

            cron_manager.RunOnce(token=self.token)

            cron_job1 = cron_manager.ReadJob(cron_job_id1, token=self.token)
            cron_job2 = cron_manager.ReadJob(cron_job_id2, token=self.token)

            self.assertEqual(cron_job1.cron_args.start_time, start_time1)

            # Flow without a start time should now be running
            self.assertFalse(
                cron_manager.JobIsRunning(cron_job1, token=self.token))
            self.assertTrue(
                cron_manager.JobIsRunning(cron_job2, token=self.token))

        # Move the clock past the start time
        with test_lib.FakeTime(500):

            cron_manager.RunOnce(token=self.token)

            cron_job1 = cron_manager.ReadJob(cron_job_id1, token=self.token)
            cron_job2 = cron_manager.ReadJob(cron_job_id2, token=self.token)

            # Start time should be the same
            self.assertEqual(cron_job1.cron_args.start_time, start_time1)

            # Now both should be running
            self.assertTrue(
                cron_manager.JobIsRunning(cron_job1, token=self.token))
            self.assertTrue(
                cron_manager.JobIsRunning(cron_job2, token=self.token))

            # Check setting a bad run id is handled.
            data_store.REL_DB.UpdateCronJob(cron_job2.job_id,
                                            current_run_id=12345)

            cron_job2 = cron_manager.ReadJob(cron_job_id2, token=self.token)
            self.assertFalse(
                cron_manager.JobIsRunning(cron_job2, token=self.token))

            # Job got updated right away.
            self.assertFalse(cron_job2.current_run_id)

            # DB also reflects the removed run id.
            cron_job2 = cron_manager.ReadJob(cron_job_id2, token=self.token)
            self.assertFalse(cron_job2.current_run_id)
Esempio n. 2
0
  def testCronJobRespectsStartTime(self):
    with test_lib.FakeTime(0):
      cron_manager = aff4_cronjobs.GetCronManager()
      start_time1 = rdfvalue.RDFDatetime(100 * 1000 * 1000)
      cron_args1 = rdf_cronjobs.CreateCronJobFlowArgs(start_time=start_time1)
      cron_args1.flow_runner_args.flow_name = "FakeCronJob"

      cron_args2 = rdf_cronjobs.CreateCronJobFlowArgs()
      cron_args2.flow_runner_args.flow_name = "FakeCronJob"

      cron_job_id1 = cron_manager.CreateJob(cron_args1, token=self.token)
      cron_job_id2 = cron_manager.CreateJob(cron_args2, token=self.token)

      cron_manager.RunOnce(token=self.token)

      cron_job1 = cron_manager.ReadJob(cron_job_id1, token=self.token)
      cron_job2 = cron_manager.ReadJob(cron_job_id2, token=self.token)

      self.assertEqual(
          cron_job1.Get(cron_job1.Schema.CRON_ARGS).start_time, start_time1)

      # Flow without a start time should now be running
      self.assertFalse(cron_job1.IsRunning())
      self.assertTrue(cron_job2.IsRunning())

    # Move the clock past the start time
    with test_lib.FakeTime(500):

      cron_manager.RunOnce(token=self.token)

      cron_job1 = cron_manager.ReadJob(cron_job_id1, token=self.token)
      cron_job2 = cron_manager.ReadJob(cron_job_id2, token=self.token)

      # Start time should be the same
      self.assertEqual(
          cron_job1.Get(cron_job1.Schema.CRON_ARGS).start_time, start_time1)

      # Now both should be running
      self.assertTrue(cron_job1.IsRunning())
      self.assertTrue(cron_job2.IsRunning())

      # Check setting a bad flow urn is handled and removed
      with aff4.FACTORY.OpenWithLock(
          cron_job2.urn, aff4_type=aff4_cronjobs.CronJob,
          token=self.token) as cron_job2:

        cron_job2.Set(cron_job2.Schema.CURRENT_FLOW_URN("aff4:/does/not/exist"))
        self.assertFalse(cron_job2.IsRunning())

      cron_job2 = cron_manager.ReadJob(cron_job_id2, token=self.token)
      self.assertFalse(cron_job2.Get(cron_job2.Schema.CURRENT_FLOW_URN))
Esempio n. 3
0
    def Run(self):
        with test_lib.FakeTime(42):
            self.CreateAdminUser("requestor")

            cron_manager = aff4_cronjobs.GetCronManager()
            cron_args = rdf_cronjobs.CreateCronJobFlowArgs(
                periodicity="1d", allow_overruns=False)
            cron_id = cron_manager.CreateJob(cron_args=cron_args,
                                             token=self.token)

        with test_lib.FakeTime(44):
            approval_id = self.RequestCronJobApproval(
                cron_id,
                approver=self.token.username,
                requestor="requestor",
                reason="foo")

        with test_lib.FakeTime(126):
            self.Check("GrantCronJobApproval",
                       args=user_plugin.ApiGrantCronJobApprovalArgs(
                           cron_job_id=cron_id,
                           approval_id=approval_id,
                           username="******"),
                       replace={
                           cron_id: "CronJob_123456",
                           approval_id: "approval:111111"
                       })
Esempio n. 4
0
  def testLastRunStatusGetsUpdatedOnEveryRun(self):
    cron_manager = aff4_cronjobs.GetCronManager()
    cron_args = rdf_cronjobs.CreateCronJobFlowArgs()
    cron_args.flow_runner_args.flow_name = "OccasionallyFailingFakeCronJob"
    cron_args.periodicity = "30s"

    job_id = cron_manager.CreateJob(cron_args=cron_args, token=self.token)

    for fake_time in [0, 60]:
      with test_lib.FakeTime(fake_time):
        # This call should start a new cron job flow
        cron_manager.RunOnce(token=self.token)
        cron_job = cron_manager.ReadJob(job_id, token=self.token)
        cron_flow_urn = cron_job.Get(cron_job.Schema.CURRENT_FLOW_URN)
        flow_test_lib.TestFlowHelper(
            cron_flow_urn, check_flow_errors=False, token=self.token)
        # This RunOnce call should determine that the flow has finished
        cron_manager.RunOnce(token=self.token)

    cron_job = cron_manager.ReadJob(job_id, token=self.token)
    statuses = list(
        cron_job.GetValuesForAttribute(cron_job.Schema.LAST_RUN_STATUS))

    statuses = sorted(statuses, key=lambda x: x.age)
    self.assertEqual(len(statuses), 2)

    self.assertEqual(statuses[0].age,
                     rdfvalue.RDFDatetime.FromSecondsSinceEpoch(0))
    self.assertEqual(statuses[1].age,
                     rdfvalue.RDFDatetime.FromSecondsSinceEpoch(60))
    self.assertEqual(statuses[0].status,
                     rdf_cronjobs.CronJobRunStatus.Status.OK)
    self.assertEqual(statuses[1].status,
                     rdf_cronjobs.CronJobRunStatus.Status.ERROR)
Esempio n. 5
0
    def testCronJobRunAllowsOverrunsWhenAllowOverrunsIsTrue(self):
        with test_lib.FakeTime(0):
            cron_manager = aff4_cronjobs.GetCronManager()
            cron_args = rdf_cronjobs.CreateCronJobFlowArgs(allow_overruns=True,
                                                           periodicity="1h")

            cron_args.flow_runner_args.flow_name = "FakeCronJobRel"

            job_id = cron_manager.CreateJob(cron_args=cron_args)

            cron_manager.RunOnce(token=self.token)

            cron_job_runs = cron_manager.ReadJobRuns(job_id, token=self.token)
            self.assertEqual(len(cron_job_runs), 1)

            # Let an hour pass. Frequency is 1h (i.e. cron job iterations are
            # supposed to be started every hour), so the new flow should be started
            # by RunOnce(). Previous iteration flow hasn't finished yet, but
            # allow_overruns is True, so it's ok to start new iteration.
            time.time = lambda: 60 * 60 + 1

            cron_manager.RunOnce(token=self.token)

            cron_job_runs = cron_manager.ReadJobRuns(job_id, token=self.token)
            self.assertEqual(len(cron_job_runs), 2)
Esempio n. 6
0
    def testLatencyStatsAreCorrectlyRecorded(self):
        with test_lib.FakeTime(0):
            cron_manager = aff4_cronjobs.GetCronManager()
            cron_args = rdf_cronjobs.CreateCronJobFlowArgs()
            cron_args.flow_runner_args.flow_name = "FakeCronJobRel"
            cron_args.periodicity = "1w"

            cron_job_id = cron_manager.CreateJob(cron_args=cron_args)

            cron_manager.RunOnce(token=self.token)

        prev_metric_value = stats.STATS.GetMetricValue("cron_job_latency",
                                                       fields=[cron_job_id])

        # Fast forward one minute
        with test_lib.FakeTime(60):
            cron_manager.RunOnce(token=self.token)
            run_urn = cron_manager.ReadJobRuns(cron_job_id)[-1].urn
            flow_test_lib.TestFlowHelper(run_urn,
                                         check_flow_errors=False,
                                         token=self.token)

            # This RunOnce call should determine that the flow has finished
            cron_manager.RunOnce(token=self.token)

        # Check that stats got updated
        current_metric_value = stats.STATS.GetMetricValue("cron_job_latency",
                                                          fields=[cron_job_id])
        self.assertEqual(current_metric_value.count - prev_metric_value.count,
                         1)
        self.assertEqual(current_metric_value.sum - prev_metric_value.sum, 60)
Esempio n. 7
0
    def testLastRunStatusGetsUpdated(self):
        cron_manager = aff4_cronjobs.GetCronManager()
        cron_args = rdf_cronjobs.CreateCronJobFlowArgs()
        cron_args.flow_runner_args.flow_name = "OccasionallyFailingFakeCronJobRel"
        cron_args.periodicity = "30s"

        job_id = cron_manager.CreateJob(cron_args=cron_args)

        statuses = []
        for fake_time in [0, 60]:
            with test_lib.FakeTime(fake_time):
                # This call should start a new cron job flow
                cron_manager.RunOnce(token=self.token)
                run_urn = cron_manager.ReadJobRuns(job_id)[-1].urn
                flow_test_lib.TestFlowHelper(run_urn,
                                             check_flow_errors=False,
                                             token=self.token)
                # This RunOnce call should determine that the flow has finished
                cron_manager.RunOnce(token=self.token)

                cron_job = cron_manager.ReadJob(job_id, token=self.token)
                statuses.append(cron_job.last_run_status)

        statuses = sorted(statuses, key=lambda x: x.age)
        self.assertEqual(len(statuses), 2)

        self.assertEqual(statuses[0], rdf_cronjobs.CronJobRunStatus.Status.OK)
        self.assertEqual(statuses[1],
                         rdf_cronjobs.CronJobRunStatus.Status.ERROR)
Esempio n. 8
0
    def testCronJobPreservesFlowNameAndArguments(self):
        """Testing initialization of a ConfigManager."""
        pathspec = rdf_paths.PathSpec(path="/foo",
                                      pathtype=rdf_paths.PathSpec.PathType.TSK)

        cron_manager = aff4_cronjobs.GetCronManager()

        cron_args = rdf_cronjobs.CreateCronJobFlowArgs(periodicity="1d",
                                                       allow_overruns=False)

        cron_args.flow_runner_args.flow_name = transfer.GetFile.__name__
        cron_args.flow_args.pathspec = pathspec

        job_id = cron_manager.CreateJob(cron_args=cron_args)

        # Check that CronJob definition is saved properly
        jobs = cron_manager.ListJobs(token=self.token)
        self.assertEqual(len(jobs), 1)
        self.assertEqual(jobs[0], job_id)

        cron_job = cron_manager.ReadJob(job_id, token=self.token)
        self.assertEqual(cron_job.cron_args.flow_runner_args.flow_name,
                         transfer.GetFile.__name__)

        self.assertEqual(cron_job.cron_args.flow_args.pathspec, pathspec)

        self.assertEqual(cron_job.cron_args.periodicity,
                         rdfvalue.Duration("1d"))
        self.assertEqual(cron_job.cron_args.allow_overruns, False)
Esempio n. 9
0
    def Run(self):
        with test_lib.FakeTime(42):
            self.CreateUser("approver")

        cron_manager = aff4_cronjobs.GetCronManager()
        cron_args = rdf_cronjobs.CreateCronJobFlowArgs(periodicity="1d",
                                                       allow_overruns=False)
        cron_id = cron_manager.CreateJob(cron_args=cron_args, token=self.token)

        def ReplaceCronAndApprovalIds():
            approvals = self.ListCronJobApprovals()
            return {
                approvals[0].id: "approval:112233",
                cron_id: "CronJob_123456"
            }

        with test_lib.FakeTime(126):
            self.Check("CreateCronJobApproval",
                       args=user_plugin.ApiCreateCronJobApprovalArgs(
                           cron_job_id=cron_id,
                           approval=user_plugin.ApiCronJobApproval(
                               reason="really important reason!",
                               notified_users=["approver1", "approver2"],
                               email_cc_addresses=["*****@*****.**"])),
                       replace=ReplaceCronAndApprovalIds)
Esempio n. 10
0
def ScheduleSystemCronFlows(names=None, token=None):
  """Schedule all the SystemCronFlows found."""

  if data_store.RelationalDBReadEnabled(category="cronjobs"):
    return cronjobs.ScheduleSystemCronJobs(names=names)

  errors = []
  for name in config.CONFIG["Cron.disabled_system_jobs"]:
    try:
      cls = registry.FlowRegistry.FlowClassByName(name)
    except ValueError:
      errors.append("No such flow: %s." % name)
      continue

    if not aff4.issubclass(cls, SystemCronFlow):
      errors.append("Disabled system cron job name doesn't correspond to "
                    "a flow inherited from SystemCronFlow: %s" % name)

  if names is None:
    names = iterkeys(registry.FlowRegistry.FLOW_REGISTRY)

  for name in names:
    cls = registry.FlowRegistry.FlowClassByName(name)

    if not aff4.issubclass(cls, SystemCronFlow):
      continue

    cron_args = rdf_cronjobs.CreateCronJobFlowArgs(
        periodicity=cls.frequency,
        lifetime=cls.lifetime,
        allow_overruns=cls.allow_overruns)
    cron_args.flow_runner_args.flow_name = name

    if cls.enabled:
      enabled = name not in config.CONFIG["Cron.disabled_system_jobs"]
    else:
      enabled = False

    job_urn = CronManager.CRON_JOBS_PATH.Add(name)
    with aff4.FACTORY.Create(
        job_urn,
        aff4_type=CronJob,
        mode="rw",
        token=token,
        force_new_version=False) as cron_job:

      # If the cronjob was already present we don't want to overwrite the
      # original start_time.
      existing_cron_args = cron_job.Get(cron_job.Schema.CRON_ARGS)

      if cron_args != existing_cron_args:
        cron_job.Set(cron_job.Schema.CRON_ARGS(cron_args))

      cron_job.Set(cron_job.Schema.DISABLED(not enabled))

  if errors:
    raise ValueError(
        "Error(s) while parsing Cron.disabled_system_jobs: %s" % errors)
Esempio n. 11
0
  def CreateJob(self, cron_args=None, job_id=None, token=None, enabled=True):
    """Creates a cron job that runs given flow with a given frequency.

    Args:
      cron_args: A protobuf of type rdf_cronjobs.CreateCronJobArgs.

      job_id: Use this job_id instead of an autogenerated unique name (used
              for system cron jobs - we want them to have well-defined
              persistent name).

      token: Security token used for data store access.

      enabled: If False, the job object will be created, but will be disabled.

    Returns:
      Name of the cron job created.
    """
    if not job_id:
      uid = utils.PRNG.GetUInt16()
      job_id = "%s_%s" % (cron_args.flow_name, uid)

    flow_runner_args = rdf_flow_runner.FlowRunnerArgs(
        flow_name="CreateAndRunGenericHuntFlow")

    flow_args = rdf_hunts.CreateGenericHuntFlowArgs()
    flow_args.hunt_args.flow_args = cron_args.flow_args
    flow_args.hunt_args.flow_runner_args.flow_name = cron_args.flow_name
    flow_args.hunt_runner_args = cron_args.hunt_runner_args
    flow_args.hunt_runner_args.hunt_name = "GenericHunt"

    create_cron_args = rdf_cronjobs.CreateCronJobFlowArgs(
        description=cron_args.description,
        periodicity=cron_args.frequency,
        flow_runner_args=flow_runner_args,
        flow_args=flow_args,
        allow_overruns=cron_args.allow_overruns,
        lifetime=cron_args.lifetime)

    cron_job_urn = self.CRON_JOBS_PATH.Add(job_id)
    with aff4.FACTORY.Create(
        cron_job_urn,
        aff4_type=CronJob,
        mode="rw",
        token=token,
        force_new_version=False) as cron_job:

      # If the cronjob was already present we don't want to overwrite the
      # original start_time.
      existing_cron_args = cron_job.Get(cron_job.Schema.CRON_ARGS)
      if existing_cron_args and existing_cron_args.start_time:
        create_cron_args.start_time = existing_cron_args.start_time

      if create_cron_args != existing_cron_args:
        cron_job.Set(cron_job.Schema.CRON_ARGS(create_cron_args))

      cron_job.Set(cron_job.Schema.DISABLED(not enabled))

    return job_id
Esempio n. 12
0
    def testSchedulingJobWithFixedNamePreservesTheName(self):
        cron_manager = aff4_cronjobs.GetCronManager()
        cron_args = rdf_cronjobs.CreateCronJobFlowArgs(allow_overruns=True,
                                                       periodicity="1d")

        cron_args.flow_runner_args.flow_name = "FakeCronJobRel"

        job_id = cron_manager.CreateJob(cron_args=cron_args, job_id="TheJob")
        self.assertEqual("TheJob", job_id)
Esempio n. 13
0
    def setUp(self):
        super(ApiListCronJobRunsHandlerRegressionTest, self).setUp()

        with test_lib.FakeTime(44):
            cron_args = rdf_cronjobs.CreateCronJobFlowArgs(periodicity="7d",
                                                           lifetime="1d")
            cron_args.flow_runner_args.flow_name = self.flow_name
            cronjobs.GetCronManager().CreateJob(cron_args,
                                                job_id=self.flow_name,
                                                token=self.token)

            cronjobs.GetCronManager().RunOnce(token=self.token)
Esempio n. 14
0
    def testTerminateExpiredRun(self):
        with test_lib.FakeTime(0):
            cron_manager = aff4_cronjobs.GetCronManager()
            cron_args = rdf_cronjobs.CreateCronJobFlowArgs()
            cron_args.flow_runner_args.flow_name = "FakeCronJobRel"
            cron_args.periodicity = "1w"
            cron_args.lifetime = FakeCronJobRel.lifetime

            job_id = cron_manager.CreateJob(cron_args=cron_args)

            cron_manager.RunOnce(token=self.token)

            cron_job = cron_manager.ReadJob(job_id, token=self.token)
            self.assertTrue(
                cron_manager.JobIsRunning(cron_job, token=self.token))
            self.assertFalse(cron_manager.TerminateExpiredRun(cron_job))

        prev_timeout_value = stats.STATS.GetMetricValue("cron_job_timeout",
                                                        fields=[job_id])
        prev_latency_value = stats.STATS.GetMetricValue("cron_job_latency",
                                                        fields=[job_id])

        # Fast forward one day
        with test_lib.FakeTime(24 * 60 * 60 + 1):
            flow_urn = cron_manager.ReadJobRuns(job_id)[-1].urn

            cron_manager.RunOnce(token=self.token)
            cron_job = cron_manager.ReadJob(job_id, token=self.token)
            self.assertFalse(
                cron_manager.JobIsRunning(cron_job, token=self.token))

            # Check the termination log
            log_collection = flow.GRRFlow.LogCollectionForFID(flow_urn)

            for line in log_collection:
                if line.urn == flow_urn:
                    self.assertTrue(
                        "lifetime exceeded" in str(line.log_message))

            # Check that timeout counter got updated.
            current_timeout_value = stats.STATS.GetMetricValue(
                "cron_job_timeout", fields=[job_id])
            self.assertEqual(current_timeout_value - prev_timeout_value, 1)

            # Check that latency stat got updated.
            current_latency_value = stats.STATS.GetMetricValue(
                "cron_job_latency", fields=[job_id])
            self.assertEqual(
                current_latency_value.count - prev_latency_value.count, 1)
            self.assertEqual(
                current_latency_value.sum - prev_latency_value.sum,
                24 * 60 * 60 + 1)
Esempio n. 15
0
def ScheduleSystemCronFlows(names=None, token=None):
    """Schedule all the SystemCronFlows found."""

    errors = []
    for name in config.CONFIG["Cron.disabled_system_jobs"]:
        try:
            cls = registry.FlowRegistry.FlowClassByName(name)
        except ValueError:
            errors.append("No such flow: %s." % name)
            continue

        if not aff4.issubclass(cls, SystemCronFlow):
            errors.append(
                "Disabled system cron job name doesn't correspond to "
                "a flow inherited from SystemCronFlow: %s" % name)

    if names is None:
        names = registry.FlowRegistry.FLOW_REGISTRY.keys()

    for name in names:
        cls = registry.FlowRegistry.FlowClassByName(name)

        if aff4.issubclass(cls, SystemCronFlow):
            cron_args = rdf_cronjobs.CreateCronJobFlowArgs(
                periodicity=cls.frequency)
            cron_args.flow_runner_args.flow_name = name
            cron_args.lifetime = cls.lifetime
            cron_args.allow_overruns = cls.allow_overruns
            cron_args.start_time = GetStartTime(cls)

            if cls.disabled:
                disabled = True
            else:
                disabled = name in config.CONFIG["Cron.disabled_system_jobs"]

            manager = GetCronManager()
            if data_store.RelationalDBReadEnabled(category="cronjobs"):
                manager.CreateJob(cron_args=cron_args,
                                  job_id=name,
                                  disabled=disabled)
            else:
                manager.CreateJob(cron_args=cron_args,
                                  job_id=name,
                                  token=token,
                                  disabled=disabled)

    if errors:
        raise ValueError(
            "Error(s) while parsing Cron.disabled_system_jobs: %s" % errors)
Esempio n. 16
0
    def testRendersRequestedCronJobApproval(self):
        cron_manager = aff4_cronjobs.GetCronManager()
        cron_args = rdf_cronjobs.CreateCronJobFlowArgs(periodicity="1d",
                                                       allow_overruns=False)
        cron_job_id = cron_manager.CreateJob(cron_args=cron_args,
                                             token=self.token)

        self.RequestCronJobApproval(cron_job_id,
                                    reason=self.token.reason,
                                    approver="approver",
                                    requestor=self.token.username)

        args = user_plugin.ApiListCronJobApprovalsArgs()
        result = self.handler.Handle(args, token=self.token)

        self.assertEqual(len(result.items), 1)
Esempio n. 17
0
    def setUp(self):
        super(TestCronView, self).setUp()

        for flow_name in [
                cron_system.GRRVersionBreakDown.__name__,
                cron_system.OSBreakDown.__name__,
                cron_system.LastAccessStats.__name__
        ]:
            cron_args = rdf_cronjobs.CreateCronJobFlowArgs(periodicity="7d",
                                                           lifetime="1d")
            cron_args.flow_runner_args.flow_name = flow_name
            cronjobs.GetCronManager().CreateJob(cron_args,
                                                job_id=flow_name,
                                                token=self.token)

        cronjobs.GetCronManager().RunOnce(token=self.token)
Esempio n. 18
0
    def CreateCronJob(self,
                      flow_name,
                      periodicity="1d",
                      lifetime="7d",
                      description="",
                      disabled=False,
                      token=None):
        cron_args = rdf_cronjobs.CreateCronJobFlowArgs(periodicity=periodicity,
                                                       lifetime=lifetime,
                                                       description=description)
        cron_args.flow_runner_args.flow_name = flow_name

        return cronjobs.GetCronManager().CreateJob(cron_args,
                                                   job_id=flow_name,
                                                   disabled=disabled,
                                                   token=token)
Esempio n. 19
0
    def testStatefulSystemCronFlowMaintainsState(self):
        DummyStatefulSystemCronJobRel.VALUES = []

        # We need to have a cron job started to have a place to maintain
        # state.
        cron_manager = aff4_cronjobs.GetCronManager()
        cron_args = rdf_cronjobs.CreateCronJobFlowArgs()
        cron_args.flow_runner_args.flow_name = "DummyStatefulSystemCronJobRel"
        cron_manager.CreateJob(job_id="RelationalStateCronJob",
                               cron_args=cron_args)
        for i in range(3):
            cron_manager.RunOnce(force=True, token=self.token)
            runs = cron_manager.ReadJobRuns("RelationalStateCronJob")
            self.assertEqual(len(runs), i + 1)
            flow_test_lib.TestFlowHelper(runs[-1].urn, token=self.token)

        self.assertListEqual(DummyStatefulSystemCronJobRel.VALUES, [0, 1, 2])
Esempio n. 20
0
    def setUp(self):
        super(ApiCreateCronJobApprovalHandlerTest, self).setUp()

        self.SetUpApprovalTest()

        cron_manager = aff4_cronjobs.GetCronManager()
        cron_args = rdf_cronjobs.CreateCronJobFlowArgs(periodicity="1d",
                                                       allow_overruns=False)
        cron_id = cron_manager.CreateJob(cron_args=cron_args, token=self.token)

        self.handler = user_plugin.ApiCreateCronJobApprovalHandler()

        self.args = user_plugin.ApiCreateCronJobApprovalArgs(
            cron_job_id=cron_id)
        self.args.approval.reason = self.token.reason
        self.args.approval.notified_users = ["approver"]
        self.args.approval.email_cc_addresses = ["*****@*****.**"]
Esempio n. 21
0
    def testCronManagerListJobsDoesNotListDeletedJobs(self):
        cron_manager = aff4_cronjobs.GetCronManager()

        cron_args = rdf_cronjobs.CreateCronJobFlowArgs(allow_overruns=True,
                                                       periodicity="1d")

        cron_args.flow_runner_args.flow_name = "FakeCronJobRel"

        cron_job_urn = cron_manager.CreateJob(cron_args=cron_args)

        cron_jobs = list(cron_manager.ListJobs(token=self.token))
        self.assertEqual(len(cron_jobs), 1)

        cron_manager.DeleteJob(cron_job_urn, token=self.token)

        cron_jobs = list(cron_manager.ListJobs(token=self.token))
        self.assertEqual(len(cron_jobs), 0)
Esempio n. 22
0
    def testCronJobRunDoesNothingIfCurrentFlowIsRunning(self):
        cron_manager = aff4_cronjobs.GetCronManager()
        cron_args = rdf_cronjobs.CreateCronJobFlowArgs(allow_overruns=False,
                                                       periodicity="1d")
        cron_args.flow_runner_args.flow_name = "FakeCronJobRel"

        job_id = cron_manager.CreateJob(cron_args=cron_args)

        cron_manager.RunOnce(token=self.token)

        cron_job_runs = cron_manager.ReadJobRuns(job_id, token=self.token)
        self.assertEqual(len(cron_job_runs), 1)

        cron_manager.RunOnce(token=self.token)

        cron_job_runs = cron_manager.ReadJobRuns(job_id, token=self.token)
        self.assertEqual(len(cron_job_runs), 1)
Esempio n. 23
0
  def testDisabledCronJobDoesNotCreateJobs(self):
    cron_manager = aff4_cronjobs.GetCronManager()
    cron_args = rdf_cronjobs.CreateCronJobFlowArgs()
    cron_args.flow_runner_args.flow_name = "FakeCronJob"

    job_id1 = cron_manager.CreateJob(cron_args, token=self.token)
    job_id2 = cron_manager.CreateJob(cron_args, token=self.token)

    cron_manager.DisableJob(job_id1, token=self.token)

    cron_manager.RunOnce(token=self.token)

    cron_job1 = cron_manager.ReadJob(job_id1, token=self.token)
    cron_job2 = cron_manager.ReadJob(job_id2, token=self.token)

    # Disabled flow shouldn't be running, while not-disabled flow should run
    # as usual.
    self.assertFalse(cron_job1.IsRunning())
    self.assertTrue(cron_job2.IsRunning())
Esempio n. 24
0
  def testReschedulingJobWithFixedNameDoesNotCreateNewObjectVersion(self):
    cron_manager = aff4_cronjobs.GetCronManager()

    cron_args = rdf_cronjobs.CreateCronJobFlowArgs(
        allow_overruns=True, periodicity="1d")
    cron_args.flow_runner_args.flow_name = "FakeCronJob"

    # Schedule cron job with a fixed name. Check that we have 1 version
    # of "TYPE" attribute.
    cron_manager.CreateJob(
        cron_args=cron_args, token=self.token, job_id="TheJob")
    cron_job = cron_manager.ReadJob("TheJob", token=self.token)
    attr_values = list(cron_job.GetValuesForAttribute(cron_job.Schema.TYPE))
    self.assertTrue(len(attr_values) == 1)

    # Reschedule the job. Check that we still have only one "TYPE" version.
    cron_manager.CreateJob(
        cron_args=cron_args, token=self.token, job_id="TheJob")
    cron_job = cron_manager.ReadJob("TheJob", token=self.token)
    attr_values = list(cron_job.GetValuesForAttribute(cron_job.Schema.TYPE))
    self.assertTrue(len(attr_values) == 1)
Esempio n. 25
0
    def testCronJobRunMonitorsRunningFlowState(self):
        cron_manager = aff4_cronjobs.GetCronManager()
        cron_args = rdf_cronjobs.CreateCronJobFlowArgs(allow_overruns=False,
                                                       periodicity="1d")
        cron_args.flow_runner_args.flow_name = "FakeCronJobRel"

        job_id = cron_manager.CreateJob(cron_args)

        # Run() wasn't called, so nothing is supposed to be running
        cron_job = cron_manager.ReadJob(job_id, token=self.token)
        self.assertFalse(cron_manager.JobIsRunning(cron_job, token=self.token))

        cron_manager.RunOnce(token=self.token)

        # Run() was called and flow was started, so the job should be
        # considered running.
        cron_job = cron_manager.ReadJob(job_id, token=self.token)
        self.assertTrue(cron_manager.JobIsRunning(cron_job, token=self.token))

        # Find the flow that is currently running for the job and terminate it.
        cron_job = cron_manager.ReadJob(job_id, token=self.token)
        self.assertTrue(cron_manager.JobIsRunning(cron_job, token=self.token))
        self.assertTrue(cron_job.current_run_id)
        runs = cron_manager.ReadJobRuns(job_id)
        self.assertTrue(runs)
        for run in runs:
            flow.GRRFlow.TerminateFlow(run.urn, token=self.token)

        # Check we're dead
        cron_job = cron_manager.ReadJob(job_id, token=self.token)
        self.assertFalse(cron_manager.JobIsRunning(cron_job, token=self.token))

        # This will understand that current flow has terminated. New flow won't be
        # started, because iterations are supposed to be started once per day
        # (frequency=1d).
        cron_manager.RunOnce(token=self.token)

        # Still dead
        cron_job = cron_manager.ReadJob(job_id, token=self.token)
        self.assertFalse(cron_manager.JobIsRunning(cron_job, token=self.token))
Esempio n. 26
0
    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"})
Esempio n. 27
0
    def Handle(self, args, token=None):
        args.flow_args.hunt_runner_args.hunt_name = "GenericHunt"

        # TODO(user): The following should be asserted in a more elegant way.
        # Also, it's not clear whether cron job scheduling UI is used often enough
        # to justify its existence. We should check with opensource users whether
        # they find this feature useful and if not, deprecate it altogether.
        if args.flow_name != standard.CreateAndRunGenericHuntFlow.__name__:
            raise ValueError(
                "Only CreateAndRunGenericHuntFlow flows are supported "
                "here (got: %s)." % args.flow_name)

        # Clear all fields marked with HIDDEN, except for output_plugins - they are
        # marked HIDDEN, because we have a separate UI for them, not because they
        # shouldn't be shown to the user at all.
        #
        # TODO(user): Refactor the code to remove the HIDDEN label from
        # FlowRunnerArgs.output_plugins.
        args.flow_runner_args.ClearFieldsWithLabel(
            rdf_structs.SemanticDescriptor.Labels.HIDDEN,
            exceptions="output_plugins")
        if not args.flow_runner_args.flow_name:
            args.flow_runner_args.flow_name = args.flow_name

        cron_args = rdf_cronjobs.CreateCronJobFlowArgs(
            description=args.description,
            periodicity=args.periodicity,
            flow_runner_args=args.flow_runner_args,
            flow_args=args.flow_args,
            allow_overruns=args.allow_overruns,
            lifetime=args.lifetime)
        name = aff4_cronjobs.GetCronManager().CreateJob(cron_args=cron_args,
                                                        disabled=True,
                                                        token=token)

        fd = aff4_cronjobs.GetCronManager().ReadJob(name)

        return ApiCronJob().InitFromObject(fd)
Esempio n. 28
0
    def testFailedFlowUpdatesStats(self):
        cron_manager = aff4_cronjobs.GetCronManager()
        cron_args = rdf_cronjobs.CreateCronJobFlowArgs(allow_overruns=False,
                                                       periodicity="1d")
        cron_args.flow_runner_args.flow_name = "FailingFakeCronJobRel"

        job_id = cron_manager.CreateJob(cron_args=cron_args)

        prev_metric_value = stats.STATS.GetMetricValue("cron_job_failure",
                                                       fields=[job_id])

        cron_manager.RunOnce(token=self.token)
        run_urn = cron_manager.ReadJobRuns(job_id)[-1].urn
        flow_test_lib.TestFlowHelper(run_urn,
                                     check_flow_errors=False,
                                     token=self.token)
        # This RunOnce call should determine that the flow has failed
        cron_manager.RunOnce(token=self.token)

        # Check that stats got updated
        current_metric_value = stats.STATS.GetMetricValue("cron_job_failure",
                                                          fields=[job_id])
        self.assertEqual(current_metric_value - prev_metric_value, 1)
Esempio n. 29
0
    def testCronJobRunDoesNothingIfDueTimeHasNotComeYet(self):
        with test_lib.FakeTime(0):
            cron_manager = aff4_cronjobs.GetCronManager()
            cron_args = rdf_cronjobs.CreateCronJobFlowArgs(
                allow_overruns=False, periodicity="1h")

            cron_args.flow_runner_args.flow_name = "FakeCronJobRel"

            job_id = cron_manager.CreateJob(cron_args=cron_args)

            cron_manager.RunOnce(token=self.token)

            cron_job_runs = cron_manager.ReadJobRuns(job_id, token=self.token)
            self.assertEqual(len(cron_job_runs), 1)

            # Let 59 minutes pass. Frequency is 1 hour, so new flow is not
            # supposed to start.
            time.time = lambda: 59 * 60

            cron_manager.RunOnce(token=self.token)

            cron_job_runs = cron_manager.ReadJobRuns(job_id, token=self.token)
            self.assertEqual(len(cron_job_runs), 1)
Esempio n. 30
0
    def testCronJobStartsFlowAndCreatesSymlinkOnRun(self):
        cron_manager = aff4_cronjobs.GetCronManager()
        cron_args = rdf_cronjobs.CreateCronJobFlowArgs()
        cron_args.flow_runner_args.flow_name = "FakeCronJobRel"

        job_id = cron_manager.CreateJob(cron_args=cron_args)

        cron_job = cron_manager.ReadJob(job_id, token=self.token)
        self.assertFalse(cron_manager.JobIsRunning(cron_job, token=self.token))
        # The job never ran, so JobDueToRun() should return true.
        self.assertTrue(cron_manager.JobDueToRun(cron_job))

        cron_manager.RunOnce(token=self.token)

        cron_job = cron_manager.ReadJob(job_id, token=self.token)
        self.assertTrue(cron_manager.JobIsRunning(cron_job, token=self.token))

        # Check that a link to the flow is created under job object.
        runs = cron_manager.ReadJobRuns(job_id, token=self.token)
        self.assertEqual(len(runs), 1)

        # Check that the link points to the correct flow.
        self.assertEqual(runs[0].runner_args.flow_name, "FakeCronJobRel")