def _CreateHuntFromHunt(self): flow_args = rdf_file_finder.FileFinderArgs( paths=["a/*", "b/*"], action=rdf_file_finder.FileFinderAction(action_type="STAT")) flow_runner_args = rdf_flow_runner.FlowRunnerArgs( flow_name=file_finder.FileFinder.__name__) client_rule_set = self._CreateForemanClientRuleSet() source_h = self.CreateHunt(flow_args=flow_args, flow_runner_args=flow_runner_args, description="foo-description", client_rule_set=client_rule_set) ref = rdf_hunts.FlowLikeObjectReference.FromHuntId( source_h.urn.Basename()) # Modify flow_args so that there are differences. flow_args.paths = ["b/*", "c/*"] client_rule_set.rules[0].regex.field = "FQDN" output_plugins = [ output_plugin.OutputPluginDescriptor( plugin_name="TestOutputPlugin") ] new_h = self.CreateHunt(flow_args=flow_args, flow_runner_args=flow_runner_args, description="bar-description", client_rule_set=client_rule_set, output_plugins=output_plugins, original_object=ref) return new_h, source_h
def _CreateHuntFromFlow(self): self.client_id = self.SetupClient(0) flow_args = rdf_file_finder.FileFinderArgs( paths=["a/*", "b/*"], action=rdf_file_finder.FileFinderAction(action_type="STAT")) flow_runner_args = rdf_flow_runner.FlowRunnerArgs( flow_name=file_finder.FileFinder.__name__) flow_urn = flow.GRRFlow.StartFlow(client_id=self.client_id, args=flow_args, runner_args=flow_runner_args, token=self.token) ref = rdf_hunts.FlowLikeObjectReference.FromFlowIdAndClientId( flow_urn.Basename(), self.client_id.Basename()) # Modify flow_args so that there are differences. flow_args.paths = ["b/*", "c/*"] flow_args.action.action_type = "DOWNLOAD" flow_args.conditions = [ rdf_file_finder.FileFinderCondition( condition_type="SIZE", size=rdf_file_finder.FileFinderSizeCondition(min_file_size=42)) ] return self.CreateHunt(flow_args=flow_args, flow_runner_args=flow_runner_args, original_object=ref), flow_urn
def setUp(self): super(ApiGetHuntFileHandlerTest, self).setUp() self.handler = hunt_plugin.ApiGetHuntFileHandler() self.file_path = os.path.join(self.base_path, "test.plist") self.hunt = implementation.GRRHunt.StartHunt( hunt_name=standard.GenericHunt.__name__, flow_runner_args=rdf_flow_runner.FlowRunnerArgs( flow_name=file_finder.FileFinder.__name__), flow_args=rdf_file_finder.FileFinderArgs( paths=[self.file_path], action=rdf_file_finder.FileFinderAction( action_type="DOWNLOAD"), ), client_rate=0, token=self.token) self.hunt.Run() self.aff4_file_path = "fs/os/%s" % self.file_path self.client_id = self.SetupClient(0) self.AssignTasksToClients(client_ids=[self.client_id]) action_mock = action_mocks.FileFinderClientMock() hunt_test_lib.TestHuntHelper(action_mock, [self.client_id], token=self.token)
def testAlertEmailIsSentWhenClientKilledDuringHunt(self): """Test that client killed messages are handled correctly for hunts.""" client_id = test_lib.TEST_CLIENT_ID self.email_messages = [] def SendEmail(address, sender, title, message, **_): self.email_messages.append( dict(address=address, sender=sender, title=title, message=message)) with hunts_implementation.GRRHunt.StartHunt( hunt_name=hunts_standard.GenericHunt.__name__, flow_runner_args=rdf_flow_runner.FlowRunnerArgs( flow_name=flow_test_lib.FlowWithOneClientRequest.__name__), client_rate=0, crash_alert_email="*****@*****.**", token=self.token) as hunt: hunt.Run() hunt.StartClients(hunt.session_id, client_id) with utils.Stubber(email_alerts.EMAIL_ALERTER, "SendEmail", SendEmail): client = flow_test_lib.CrashClientMock(client_id, self.token) hunt_test_lib.TestHuntHelper(client, [client_id], token=self.token, check_flow_errors=False) self.assertEqual(len(self.email_messages), 2) self.assertListEqual([ self.email_messages[0]["address"], self.email_messages[1]["address"] ], ["*****@*****.**", config.CONFIG["Monitoring.alert_email"]])
def Run(self): runner_args = rdf_flow_runner.FlowRunnerArgs( flow_name=transfer.GetFile.__name__) flow_args = transfer.GetFileArgs( pathspec=rdf_paths.PathSpec( path="/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.OS)) client_mock = hunt_test_lib.SampleHuntMock() with test_lib.FakeTime(42): flow_urn = flow.GRRFlow.StartFlow( client_id=self.client_id, args=flow_args, runner_args=runner_args, token=self.token) flow_test_lib.TestFlowHelper( flow_urn, client_mock=client_mock, client_id=self.client_id, token=self.token) self.Check( "ListFlowResults", args=flow_plugin.ApiListFlowResultsArgs( client_id=self.client_id.Basename(), flow_id=flow_urn.Basename()), replace={flow_urn.Basename(): "W:ABCDEF"})
def testOverviewIsShownForNestedHuntFlows(self): with implementation.GRRHunt.StartHunt( hunt_name=standard.GenericHunt.__name__, flow_runner_args=rdf_flow_runner.FlowRunnerArgs( flow_name=gui_test_lib.RecursiveTestFlow.__name__), client_rate=0, token=self.token) as hunt: hunt.Run() self.AssignTasksToClients(client_ids=[self.client_id]) self.RunHunt(client_ids=[self.client_id]) self.Open("/#/clients/%s" % self.client_id) self.Click("css=a[grrtarget='client.flows']") # There should be a RecursiveTestFlow in the list. Expand nested flows. self.Click("css=tr:contains('RecursiveTestFlow') span.tree_branch") # Click on a nested flow. self.Click("css=tr:contains('RecursiveTestFlow'):nth(2)") # Nested flow should have Depth argument set to 1. self.WaitUntil(self.IsElementPresent, "css=td:contains('Depth') ~ td:nth(0):contains('1')") # Check that flow id of this flow has forward slash - i.e. consists of # 2 components. self.WaitUntil(self.IsTextPresent, "Flow ID") flow_id = self.GetText("css=dt:contains('Flow ID') ~ dd:nth(0)") self.assertTrue("/" in flow_id)
def testBaseSessionIdFlowRunnerArgumentIsNotRespected(self): args = cron_plugin.ApiCronJob( flow_name=standard.CreateAndRunGenericHuntFlow.__name__, flow_runner_args=rdf_flow_runner.FlowRunnerArgs( base_session_id="aff4:/foo")) result = self.handler.Handle(args, token=self.token) self.assertFalse(result.flow_runner_args.HasField("base_session_id"))
def RunFlow(self, flow_name=None, plugins=None, flow_args=None, client_mock=None): runner_args = rdf_flow_runner.FlowRunnerArgs( flow_name=flow_name or transfer.GetFile.__name__, output_plugins=plugins) if flow_args is None: flow_args = transfer.GetFileArgs(pathspec=rdf_paths.PathSpec( path="/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.OS)) if client_mock is None: client_mock = hunt_test_lib.SampleHuntMock() flow_urn = flow.GRRFlow.StartFlow(client_id=self.client_id, args=flow_args, runner_args=runner_args, token=self.token) flow_test_lib.TestFlowHelper(flow_urn, client_mock=client_mock, client_id=self.client_id, token=self.token) return flow_urn
def CreateHunt(self, flow_runner_args=None, flow_args=None, client_rule_set=None, original_object=None, token=None, **kwargs): # Only initialize default flow_args value if default flow_runner_args value # is to be used. if not flow_runner_args: flow_args = ( flow_args or transfer.GetFileArgs( pathspec=rdf_paths.PathSpec( path="/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.OS))) flow_runner_args = ( flow_runner_args or rdf_flow_runner.FlowRunnerArgs(flow_name=transfer.GetFile.__name__)) client_rule_set = (client_rule_set or self._CreateForemanClientRuleSet()) return implementation.GRRHunt.StartHunt( hunt_name=standard.GenericHunt.__name__, flow_runner_args=flow_runner_args, flow_args=flow_args, client_rule_set=client_rule_set, client_rate=0, original_object=original_object, token=token or self.token, **kwargs)
def CreateSampleHunt(self, path=None, stopped=False, output_plugins=None, client_limit=0, client_count=10, token=None): token = token or self.token self.client_ids = self.SetupClients(client_count) with implementation.GRRHunt.StartHunt( hunt_name=standard.GenericHunt.__name__, flow_runner_args=rdf_flow_runner.FlowRunnerArgs( flow_name=transfer.GetFile.__name__), flow_args=transfer.GetFileArgs(pathspec=rdf_paths.PathSpec( path=path or "/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.OS, )), client_rule_set=self._CreateForemanClientRuleSet(), output_plugins=output_plugins or [], client_rate=0, client_limit=client_limit, token=token) as hunt: if not stopped: hunt.Run() foreman_obj = foreman.GetForeman(token=token) for client_id in self.client_ids: foreman_obj.AssignTasksToClient(client_id.Basename()) self.hunt_urn = hunt.urn return aff4.FACTORY.Open(hunt.urn, mode="rw", token=token, age=aff4.ALL_TIMES)
def testRunnerArgsBaseSessionIdDoesNotAffectCreatedFlow(self): """When multiple clients match, check we run on the latest one.""" flow_runner_args = rdf_flow_runner.FlowRunnerArgs( base_session_id="aff4:/foo") args = flow_plugin.ApiCreateFlowArgs( client_id=self.client_id.Basename(), flow=flow_plugin.ApiFlow(name=processes.ListProcesses.__name__, runner_args=flow_runner_args)) result = self.handler.Handle(args, token=self.token) self.assertFalse(utils.SmartStr(result.urn).startswith("aff4:/foo"))
def _StartHunt(self): with implementation.GRRHunt.StartHunt( hunt_name=standard.GenericHunt.__name__, flow_runner_args=rdf_flow_runner.FlowRunnerArgs( flow_name=flow_test_lib.FlowWithOneNestedFlow.__name__), client_rate=0, token=self.token) as hunt: hunt.Run() self.AssignTasksToClients(client_ids=[self.client_urn]) self.RunHunt(client_ids=[self.client_urn])
def _CreateHunt(self, description): output_plugins = [ output_plugin.OutputPluginDescriptor( plugin_name="TestOutputPlugin") ] with implementation.GRRHunt.StartHunt( hunt_name=standard.GenericHunt.__name__, flow_runner_args=rdf_flow_runner.FlowRunnerArgs( flow_name=transfer.GetFile.__name__), output_plugins=output_plugins, description=description, client_rate=0, token=self.token) as hunt: return hunt
def InitializeContext(self, args): """Initializes the context of this flow.""" if args is None: args = rdf_flow_runner.FlowRunnerArgs() output_plugins_states = [] for plugin_descriptor in args.output_plugins: if not args.client_id: self.Log( "Not initializing output plugin %s as flow does not run on " "the client.", plugin_descriptor.plugin_name) continue output_base_urn = self.session_id.Add(OUTPUT_PLUGIN_BASE_SUFFIX) plugin_class = plugin_descriptor.GetPluginClass() plugin = plugin_class(self.flow_obj.output_urn, args=plugin_descriptor.plugin_args, output_base_urn=output_base_urn, token=self.token) try: plugin.InitializeState() # TODO(amoser): Those do not need to be inside the state, they # could be part of the plugin descriptor. plugin.state["logs"] = [] plugin.state["errors"] = [] output_plugins_states.append( rdf_flow_runner.OutputPluginState( plugin_state=plugin.state, plugin_descriptor=plugin_descriptor)) except Exception as e: # pylint: disable=broad-except logging.info( "Plugin %s failed to initialize (%s), ignoring it.", plugin, e) parent_creator = None if self.parent_runner: parent_creator = self.parent_runner.context.creator context = rdf_flow_runner.FlowContext( create_time=rdfvalue.RDFDatetime.Now(), creator=parent_creator or self.token.username, current_state="Start", output_plugins_states=output_plugins_states, state=rdf_flow_runner.FlowContext.State.RUNNING, ) return context
def Start(self): with hunts_implementation.GRRHunt.StartHunt( hunt_name=hunts_standard.GenericHunt.__name__, client_limit=0, flow_runner_args=rdf_flow_runner.FlowRunnerArgs( flow_name=flows_discovery.Interrogate.__name__), flow_args=flows_discovery.InterrogateArgs(lightweight=False), output_plugins=self.GetOutputPlugins(), token=self.token) as hunt: runner = hunt.GetRunner() runner.runner_args.crash_limit = 500 runner.runner_args.client_rate = 50 runner.runner_args.expiry_time = "1w" runner.runner_args.description = ("Interrogate run by cron to keep host" "info fresh.") runner.Start()
def CreateSampleHunt(self, description, token=None): implementation.GRRHunt.StartHunt( hunt_name=standard.GenericHunt.__name__, description=description, flow_runner_args=rdf_flow_runner.FlowRunnerArgs( flow_name=transfer.GetFile.__name__), flow_args=transfer.GetFileArgs(pathspec=rdf_paths.PathSpec( path="/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.TSK, )), client_rule_set=self._CreateForemanClientRuleSet(), output_plugins=[ output_plugin.OutputPluginDescriptor( plugin_name="DummyOutputPlugin", plugin_args=gui_test_lib.DummyOutputPlugin.args_type( filename_regex="blah!", fetch_binaries=True)) ], client_rate=60, token=token)
def setUp(self): super(ApiGetExportedHuntResultsHandlerTest, self).setUp() self.handler = hunt_plugin.ApiGetExportedHuntResultsHandler() self.hunt = implementation.GRRHunt.StartHunt( hunt_name=standard.GenericHunt.__name__, flow_runner_args=rdf_flow_runner.FlowRunnerArgs( flow_name=flow_test_lib.DummyFlowWithSingleReply.__name__), client_rate=0, token=self.token) self.hunt.Run() self.client_ids = self.SetupClients(5) # Ensure that clients are processed sequentially - this way the test won't # depend on the order of results in the collection (which is normally # random). for cid in self.client_ids: self.AssignTasksToClients(client_ids=[cid]) client_mock = hunt_test_lib.SampleHuntMock() hunt_test_lib.TestHuntHelper(client_mock, [cid], token=self.token)
def testCopyHuntPreservesRuleType(self): implementation.GRRHunt.StartHunt( hunt_name=standard.GenericHunt.__name__, description="model hunt", flow_runner_args=rdf_flow_runner.FlowRunnerArgs( flow_name=transfer.GetFile.__name__), flow_args=transfer.GetFileArgs( pathspec=rdf_paths.PathSpec( path="/tmp/evil.txt", pathtype=rdf_paths.PathSpec.PathType.TSK, )), client_rule_set=foreman_rules.ForemanClientRuleSet(rules=[ foreman_rules.ForemanClientRule( rule_type=foreman_rules.ForemanClientRule.Type.OS, os=foreman_rules.ForemanOsClientRule(os_darwin=True)) ]), token=self.token) self.Open("/#main=ManageHunts") self.Click("css=tr:contains('model hunt')") self.Click("css=button[name=CopyHunt]:not([disabled])") # Wait until dialog appears. self.WaitUntil(self.IsElementPresent, "css=grr-wizard-form:contains('What to run?')") # Click on "Next" button self.Click("css=grr-new-hunt-wizard-form button.Next") self.WaitUntil(self.IsElementPresent, "css=grr-wizard-form:contains('Hunt parameters')") # Click on "Next" button. self.Click("css=grr-new-hunt-wizard-form button.Next") self.WaitUntil(self.IsElementPresent, "css=grr-wizard-form:contains('How to process results')") # Click on "Next" button self.Click("css=grr-new-hunt-wizard-form button.Next") self.WaitUntil(self.IsElementPresent, "css=grr-wizard-form:contains('Where to run?')") self.WaitUntil( self.IsElementPresent, "css=grr-new-hunt-wizard-form " "label:contains('Os darwin') ~ * input:checked")
def Run(self): def ReplaceFlowId(): flows_dir_fd = aff4.FACTORY.Open( self.client_id.Add("flows"), token=self.token) flow_urn = list(flows_dir_fd.ListChildren())[0] return {flow_urn.Basename(): "W:ABCDEF"} with test_lib.FakeTime(42): self.Check( "CreateFlow", args=flow_plugin.ApiCreateFlowArgs( client_id=self.client_id.Basename(), flow=flow_plugin.ApiFlow( name=processes.ListProcesses.__name__, args=processes.ListProcessesArgs( filename_regex=".", fetch_binaries=True), runner_args=rdf_flow_runner.FlowRunnerArgs( output_plugins=[], priority="HIGH_PRIORITY", notify_to_user=False))), replace=ReplaceFlowId)
def testGetPluginArgsHandlesMissingPluginsCorrectly(self): descriptor = output_plugin.OutputPluginDescriptor( plugin_name="TestOutputPluginWithArgs", plugin_args=rdf_flow_runner.FlowRunnerArgs( flow_name=transfer.GetFile.__name__)) serialized = descriptor.SerializeToString() deserialized = output_plugin.OutputPluginDescriptor() deserialized.ParseFromString(serialized) self.assertEqual(deserialized, descriptor) self.assertEqual(deserialized.GetPluginClass(), TestOutputPluginWithArgs) with utils.Stubber(output_plugin.OutputPlugin, "classes", {}): deserialized = output_plugin.OutputPluginDescriptor() deserialized.ParseFromString(serialized) self.assertTrue(deserialized.GetPluginClass(), output_plugin.UnknownOutputPlugin) # UnknownOutputPlugin should just return serialized arguments as bytes. self.assertEqual(deserialized.plugin_args, descriptor.plugin_args.SerializeToString())
def StartFlow(cls, args=None, runner_args=None, parent_flow=None, sync=True, token=None, **kwargs): """The main factory function for Creating and executing a new flow. Args: args: An arg protocol buffer which is an instance of the required flow's args_type class attribute. runner_args: an instance of FlowRunnerArgs() protocol buffer which is used to initialize the runner for this flow. parent_flow: A parent flow or None if this is a top level flow. sync: If True, the Start method of this flow will be called inline. Otherwise we schedule the starting of this flow on another worker. token: Security credentials token identifying the user. **kwargs: If args or runner_args are not specified, we construct these protobufs from these keywords. Returns: the session id of the flow. Raises: RuntimeError: Unknown or invalid parameters were provided. """ # Build the runner args from the keywords. if runner_args is None: runner_args = rdf_flow_runner.FlowRunnerArgs() cls.FilterArgsFromSemanticProtobuf(runner_args, kwargs) # When asked to run a flow in the future this implied it will run # asynchronously. if runner_args.start_time: sync = False # Is the required flow a known flow? try: flow_cls = registry.FlowRegistry.FlowClassByName( runner_args.flow_name) except ValueError: stats.STATS.IncrementCounter("grr_flow_invalid_flow_count") raise RuntimeError("Unable to locate flow %s" % runner_args.flow_name) # If no token is specified, raise. if not token: raise access_control.UnauthorizedAccess( "A token must be specified.") # For the flow itself we use a supervisor token. token = token.SetUID() # Extend the expiry time of this token indefinitely. Python on Windows only # supports dates up to the year 3000. token.expiry = rdfvalue.RDFDatetime.FromHumanReadable("2997-01-01") if flow_cls.category and not runner_args.client_id: raise RuntimeError( "Flow with category (user-visible flow) has to be " "started on a client, but runner_args.client_id " "is missing.") # We create an anonymous AFF4 object first, The runner will then generate # the appropriate URN. flow_obj = aff4.FACTORY.Create(None, flow_cls, token=token) # Now parse the flow args into the new object from the keywords. if args is None: args = flow_obj.args_type() cls.FilterArgsFromSemanticProtobuf(args, kwargs) # Check that the flow args are valid. args.Validate() # Store the flow args. flow_obj.args = args flow_obj.runner_args = runner_args # At this point we should exhaust all the keyword args. If any are left # over, we do not know what to do with them so raise. if kwargs: raise type_info.UnknownArg("Unknown parameters to StartFlow: %s" % kwargs) # Create a flow runner to run this flow with. if parent_flow: parent_runner = parent_flow.runner else: parent_runner = None runner = flow_obj.CreateRunner(parent_runner=parent_runner, runner_args=runner_args) logging.info(u"Scheduling %s(%s) on %s", flow_obj.urn, runner_args.flow_name, runner_args.client_id) if sync: # Just run the first state inline. NOTE: Running synchronously means # that this runs on the thread that starts the flow. The advantage is # that that Start method can raise any errors immediately. flow_obj.Start() else: # Running Asynchronously: Schedule the start method on another worker. runner.CallState(next_state="Start", start_time=runner_args.start_time) # The flow does not need to actually remain running. if not runner.OutstandingRequests(): flow_obj.Terminate() flow_obj.Close() # Publish an audit event, only for top level flows. if parent_flow is None: events.Events.PublishEvent("Audit", rdf_events.AuditEvent( user=token.username, action="RUN_FLOW", flow_name=runner_args.flow_name, urn=flow_obj.urn, client=runner_args.client_id), token=token) return flow_obj.urn
def testCPULimitForHunts(self): worker_obj = worker_lib.GRRWorker(token=self.token) client_ids = ["C.%016X" % i for i in xrange(10, 20)] result = {} client_mocks = [] for client_id in client_ids: client_mock = action_mocks.CPULimitClientMock(result) client_mock = flow_test_lib.MockClient( rdf_client.ClientURN(client_id), client_mock, token=self.token) client_mock.EnableResourceUsage(user_cpu_usage=[10], system_cpu_usage=[10], network_usage=[1000]) client_mocks.append(client_mock) flow_runner_args = rdf_flow_runner.FlowRunnerArgs( flow_name=flow_test_lib.CPULimitFlow.__name__) with implementation.GRRHunt.StartHunt( hunt_name=standard.GenericHunt.__name__, flow_runner_args=flow_runner_args, cpu_limit=5000, per_client_cpu_limit=10000, network_bytes_limit=1000000, client_rate=0, token=self.token) as hunt: hunt.GetRunner().Start() implementation.GRRHunt.StartClients(hunt.session_id, client_ids[:1]) self._Process(client_mocks, worker_obj) implementation.GRRHunt.StartClients(hunt.session_id, client_ids[1:2]) self._Process(client_mocks, worker_obj) implementation.GRRHunt.StartClients(hunt.session_id, client_ids[2:3]) self._Process(client_mocks, worker_obj) # The limiting factor here is the overall hunt limit of 5000 cpu # seconds. Clients that finish should decrease the remaining quota # and the following clients should get the reduced quota. self.assertEqual(result["cpulimit"], [ 5000.0, 4980.0, 4960.0, 4940.0, 4920.0, 4900.0, 4880.0, 4860.0, 4840.0 ]) self.assertEqual(result["networklimit"], [ 1000000L, 999000L, 998000L, 997000L, 996000L, 995000L, 994000L, 993000L, 992000L ]) result.clear() with implementation.GRRHunt.StartHunt( hunt_name=standard.GenericHunt.__name__, flow_runner_args=flow_runner_args, per_client_cpu_limit=3000, per_client_network_limit_bytes=3000000, client_rate=0, token=self.token) as hunt: hunt.GetRunner().Start() implementation.GRRHunt.StartClients(hunt.session_id, client_ids[:1]) self._Process(client_mocks, worker_obj) implementation.GRRHunt.StartClients(hunt.session_id, client_ids[1:2]) self._Process(client_mocks, worker_obj) implementation.GRRHunt.StartClients(hunt.session_id, client_ids[2:3]) self._Process(client_mocks, worker_obj) # This time, the per client limit is 3000s / 3000000 bytes. Every # client should get the same limit. self.assertEqual(result["cpulimit"], [ 3000.0, 2980.0, 2960.0, 3000.0, 2980.0, 2960.0, 3000.0, 2980.0, 2960.0 ]) self.assertEqual(result["networklimit"], [ 3000000, 2999000, 2998000, 3000000, 2999000, 2998000, 3000000, 2999000, 2998000 ]) result.clear() for client_mock in client_mocks: client_mock.EnableResourceUsage(user_cpu_usage=[500], system_cpu_usage=[500], network_usage=[1000000]) with implementation.GRRHunt.StartHunt( hunt_name=standard.GenericHunt.__name__, flow_runner_args=flow_runner_args, per_client_cpu_limit=3000, cpu_limit=5000, per_client_network_limit_bytes=3000000, network_bytes_limit=5000000, client_rate=0, token=self.token) as hunt: hunt.GetRunner().Start() implementation.GRRHunt.StartClients(hunt.session_id, client_ids[:1]) self._Process(client_mocks, worker_obj) implementation.GRRHunt.StartClients(hunt.session_id, client_ids[1:2]) self._Process(client_mocks, worker_obj) implementation.GRRHunt.StartClients(hunt.session_id, client_ids[2:3]) self._Process(client_mocks, worker_obj) # The first client gets the full per client limit of 3000s, and # uses all of it. The hunt has a limit of just 5000 total so the # second client gets started with a limit of 2000. It can only run # two of three states, the last client will not be started at all # due to out of quota. self.assertEqual(result["cpulimit"], [3000.0, 2000.0, 1000.0, 2000.0, 1000.0]) self.assertEqual(result["networklimit"], [3000000, 2000000, 1000000, 2000000, 1000000]) errors = list(hunt.GetClientsErrors()) self.assertEqual(len(errors), 2) # Client side out of cpu. self.assertIn("CPU limit exceeded", errors[0].log_message) # Server side out of cpu. self.assertIn("Out of CPU quota", errors[1].backtrace)
def testCopyHuntHandlesLiteralExpressionCorrectly(self): """Literals are raw bytes. Testing that raw bytes are processed right.""" literal_match = rdf_file_finder.FileFinderContentsLiteralMatchCondition( literal="foo\x0d\xc8bar") implementation.GRRHunt.StartHunt( hunt_name=standard.GenericHunt.__name__, description="model hunt", flow_runner_args=rdf_flow_runner.FlowRunnerArgs( flow_name=file_finder.FileFinder.__name__), flow_args=rdf_file_finder.FileFinderArgs( conditions=[ rdf_file_finder.FileFinderCondition( condition_type="CONTENTS_LITERAL_MATCH", contents_literal_match=literal_match) ], paths=["/tmp/evil.txt"]), token=self.token) self.Open("/#main=ManageHunts") self.Click("css=tr:contains('model hunt')") self.Click("css=button[name=CopyHunt]:not([disabled])") # Wait until dialog appears. self.WaitUntil(self.IsElementPresent, "css=grr-wizard-form:contains('What to run?')") # Check that non-default values of sample hunt are prefilled. self.WaitUntilEqual( "foo\\x0d\\xc8bar", self.GetValue, "css=grr-new-hunt-wizard-form " "label:contains('Literal') ~ * input:text") # Click on "Next" button self.Click("css=grr-new-hunt-wizard-form button.Next") self.WaitUntil(self.IsElementPresent, "css=grr-wizard-form:contains('Hunt parameters')") # Click on "Next" button. self.Click("css=grr-new-hunt-wizard-form button.Next") self.WaitUntil(self.IsElementPresent, "css=grr-wizard-form:contains('How to process results')") # Click on "Next" button self.Click("css=grr-new-hunt-wizard-form button.Next") self.WaitUntil(self.IsElementPresent, "css=grr-wizard-form:contains('Where to run?')") # Click on "Next" button self.Click("css=grr-new-hunt-wizard-form button.Next") self.WaitUntil(self.IsElementPresent, "css=grr-wizard-form:contains('Review')") # Check that the arguments summary is present. self.WaitUntil( self.IsElementPresent, "css=grr-wizard-form:contains('%s')" % file_finder.FileFinder.__name__) self.WaitUntil(self.IsTextPresent, "foo\\x0d\\xc8bar") # Click on "Run" button self.Click("css=grr-new-hunt-wizard-form button.Next") self.WaitUntil(self.IsElementPresent, "css=grr-wizard-form:contains('Created Hunt')") # Close the window and check that the hunt was created. self.Click("css=button.Next") hunts_root = aff4.FACTORY.Open("aff4:/hunts", token=self.token) hunts_list = sorted(list(hunts_root.ListChildren()), key=lambda x: x.age) self.assertEqual(len(hunts_list), 2) last_hunt = aff4.FACTORY.Open(hunts_list[-1], token=self.token) # Check that the hunt was created with a correct literal value. self.assertEqual(last_hunt.args.flow_runner_args.flow_name, file_finder.FileFinder.__name__) self.assertEqual( last_hunt.args.flow_args.conditions[0].contents_literal_match.literal, "foo\x0d\xc8bar")