Beispiel #1
0
    def testDrainTaskSchedulerQueue(self):
        client_id = u"C.1234567890123456"
        flow_id = flow.RandomFlowId()
        data_store.REL_DB.WriteClientMetadata(client_id,
                                              fleetspeak_enabled=False)

        rdf_flow = rdf_flow_objects.Flow(
            client_id=client_id,
            flow_id=flow_id,
            create_time=rdfvalue.RDFDatetime.Now())
        data_store.REL_DB.WriteFlowObject(rdf_flow)

        action_requests = []
        for i in range(3):
            data_store.REL_DB.WriteFlowRequests([
                rdf_flow_objects.FlowRequest(client_id=client_id,
                                             flow_id=flow_id,
                                             request_id=i)
            ])

            action_requests.append(
                rdf_flows.ClientActionRequest(client_id=client_id,
                                              flow_id=flow_id,
                                              request_id=i,
                                              action_identifier="WmiQuery"))

        data_store.REL_DB.WriteClientActionRequests(action_requests)
        server = TestServer()

        res = server.DrainTaskSchedulerQueueForClient(
            rdfvalue.RDFURN(client_id))
        msgs = [
            rdf_flow_objects.GRRMessageFromClientActionRequest(r)
            for r in action_requests
        ]
        for r in res:
            r.task_id = 0
        for m in msgs:
            m.task_id = 0

        self.assertItemsEqual(res, msgs)
Beispiel #2
0
    def CallClient(self,
                   action_cls: Type[server_stubs.ClientActionStub],
                   request: Optional[rdfvalue.RDFValue] = None,
                   next_state: Optional[str] = None,
                   callback_state: Optional[str] = None,
                   request_data: Optional[Mapping[str, Any]] = None,
                   **kwargs: Any):
        """Calls the client asynchronously.

    This sends a message to the client to invoke an Action. The run action may
    send back many responses that will be queued by the framework until a status
    message is sent by the client. The status message will cause the entire
    transaction to be committed to the specified state.

    Args:
       action_cls: The function to call on the client.
       request: The request to send to the client. If not specified, we create a
         new RDFValue using the kwargs.
       next_state: The state in this flow, that responses to this message should
         go to.
       callback_state: (optional) The state to call whenever a new response is
         arriving.
       request_data: A dict which will be available in the RequestState
         protobuf. The Responses object maintains a reference to this protobuf
         for use in the execution of the state method. (so you can access this
         data by responses.request).
       **kwargs: These args will be used to construct the client action argument
         rdfvalue.

    Raises:
       ValueError: The request passed to the client does not have the correct
                   type.
    """
        try:
            action_identifier = action_registry.ID_BY_ACTION_STUB[action_cls]
        except KeyError:
            raise ValueError("Action class %s not known." % action_cls)

        if action_cls.in_rdfvalue is None:
            if request:
                raise ValueError("Client action %s does not expect args." %
                                 action_cls)
        else:
            if request is None:
                # Create a new rdf request.
                request = action_cls.in_rdfvalue(**kwargs)
            else:
                # Verify that the request type matches the client action requirements.
                if not isinstance(request, action_cls.in_rdfvalue):
                    raise ValueError("Client action expected %s but got %s" %
                                     (action_cls.in_rdfvalue, type(request)))

        outbound_id = self.GetNextOutboundId()

        # Create a flow request.
        flow_request = rdf_flow_objects.FlowRequest(
            client_id=self.rdf_flow.client_id,
            flow_id=self.rdf_flow.flow_id,
            request_id=outbound_id,
            next_state=next_state,
            callback_state=callback_state)

        if request_data is not None:
            flow_request.request_data = rdf_protodict.Dict().FromDict(
                request_data)

        cpu_limit_ms = None
        network_bytes_limit = None

        if self.rdf_flow.cpu_limit:
            cpu_usage = self.rdf_flow.cpu_time_used
            cpu_limit_ms = 1000 * max(
                self.rdf_flow.cpu_limit - cpu_usage.user_cpu_time -
                cpu_usage.system_cpu_time, 0)

            if cpu_limit_ms == 0:
                raise flow.FlowResourcesExceededError(
                    "CPU limit exceeded for {} {}.".format(
                        self.rdf_flow.flow_class_name, self.rdf_flow.flow_id))

        if self.rdf_flow.network_bytes_limit:
            network_bytes_limit = max(
                self.rdf_flow.network_bytes_limit -
                self.rdf_flow.network_bytes_sent, 0)
            if network_bytes_limit == 0:
                raise flow.FlowResourcesExceededError(
                    "Network limit exceeded for {} {}.".format(
                        self.rdf_flow.flow_class_name, self.rdf_flow.flow_id))

        runtime_limit_us = self.rdf_flow.runtime_limit_us

        if runtime_limit_us and self.rdf_flow.runtime_us:
            if self.rdf_flow.runtime_us < runtime_limit_us:
                runtime_limit_us -= self.rdf_flow.runtime_us
            else:
                raise flow.FlowResourcesExceededError(
                    "Runtime limit exceeded for {} {}.".format(
                        self.rdf_flow.flow_class_name, self.rdf_flow.flow_id))

        client_action_request = rdf_flows.ClientActionRequest(
            client_id=self.rdf_flow.client_id,
            flow_id=self.rdf_flow.flow_id,
            request_id=outbound_id,
            action_identifier=action_identifier,
            action_args=request,
            cpu_limit_ms=cpu_limit_ms,
            network_bytes_limit=network_bytes_limit,
            runtime_limit_us=runtime_limit_us)

        self.flow_requests.append(flow_request)
        self.client_action_requests.append(client_action_request)