def _AwaitFlow(self, client, flow_id): """Waits for a specific GRR flow to complete. Args: client (object): GRR Client object in which to await the flow. flow_id (str): GRR identifier of the flow to await. Raises: DFTimewolfError: if flow error encountered. """ print('{0:s}: Waiting to finish'.format(flow_id)) while True: try: status = client.Flow(flow_id).Get().data except grr_errors.UnknownError: msg = 'Unable to stat flow {0:s} for host {1:s}'.format( flow_id, client.data.os_info.fqdn.lower()) self.state.AddError(msg) raise DFTimewolfError( 'Unable to stat flow {0:s} for host {1:s}'.format( flow_id, client.data.os_info.fqdn.lower())) if status.state == flows_pb2.FlowContext.ERROR: # TODO(jbn): If one artifact fails, what happens? Test. message = status.context.backtrace if 'ArtifactNotRegisteredError' in status.context.backtrace: message = status.context.backtrace.split('\n')[-2] raise DFTimewolfError( '{0:s}: FAILED! Message from GRR:\n{1:s}'.format( flow_id, message)) if status.state == flows_pb2.FlowContext.TERMINATED: print('{0:s}: Complete'.format(flow_id)) break time.sleep(self._CHECK_FLOW_INTERVAL_SEC)
def _AwaitFlow(self, client, flow_id): """Waits for a specific GRR flow to complete. Args: client (object): GRR Client object in which to await the flow. flow_id (str): GRR identifier of the flow to await. Raises: DFTimewolfError: If a Flow error was encountered. """ self.logger.info('{0:s}: Waiting to finish'.format(flow_id)) if self.skip_offline_clients: self.logger.info('Client will be skipped if offline.') while True: try: status = client.Flow(flow_id).Get().data except grr_errors.UnknownError: msg = 'Unable to stat flow {0:s} for host {1:s}'.format( flow_id, client.data.os_info.fqdn.lower()) self.ModuleError(msg, critical=True) if status.state == flows_pb2.FlowContext.ERROR: # TODO(jbn): If one artifact fails, what happens? Test. message = status.context.backtrace if 'ArtifactNotRegisteredError' in status.context.backtrace: message = status.context.backtrace.split('\n')[-2] raise DFTimewolfError( '{0:s}: FAILED! Message from GRR:\n{1:s}'.format( flow_id, message)) if status.state == flows_pb2.FlowContext.TERMINATED: self.logger.info('{0:s}: Complete'.format(flow_id)) break time.sleep(self._CHECK_FLOW_INTERVAL_SEC) if not self.skip_offline_clients: continue client_last_seen = datetime.datetime.fromtimestamp( client.data.last_seen_at / 1000000, datetime.timezone.utc) now = datetime.datetime.now(datetime.timezone.utc) if (now - client_last_seen ).total_seconds() > self._MAX_OFFLINE_TIME_SEC: self.logger.warning( 'Client {0:s} has been offline for more than {1:.1f} minutes' ', skipping...'.format(client.client_id, self._MAX_OFFLINE_TIME_SEC / 60)) self._skipped_flows.append((client.client_id, flow_id)) break
def testProcessErrors(self, mock_exit, mock_process1, mock_process2): """Tests that module's errors arre correctly caught.""" test_state = state.DFTimewolfState(config.Config) test_state.load_recipe(test_recipe.contents) test_state.setup_modules(DummyArgs()) mock_process1.side_effect = Exception('asd') mock_process2.side_effect = DFTimewolfError('dfTimewolf Error') test_state.run_modules() mock_process1.assert_called_with() mock_process2.assert_called_with() mock_exit.assert_called_with(-1) self.assertEqual(len(test_state.global_errors), 2) msg, critical = sorted(test_state.global_errors, key=lambda x: x[0])[0] self.assertIn('An unknown error occurred: asd', msg) self.assertTrue(critical) msg, critical = sorted(test_state.global_errors, key=lambda x: x[0])[1] self.assertIn('dfTimewolf Error', msg) self.assertTrue(critical)