def _GetLastContactFromFleetspeak(client_ids): """Fetches last contact times for the given clients from Fleetspeak. Args: client_ids: Iterable containing GRR client ids. Returns: A dict mapping the given client ids to timestamps representing when Fleetspeak last contacted the clients. """ if not fleetspeak_connector.CONN or not fleetspeak_connector.CONN.outgoing: logging.warning( "Tried to get last-contact timestamps for Fleetspeak clients " "without an active connection to Fleetspeak.") return {} fs_ids = [fleetspeak_utils.GRRIDToFleetspeakID(cid) for cid in client_ids] fs_result = fleetspeak_connector.CONN.outgoing.ListClients( admin_pb2.ListClientsRequest(client_ids=fs_ids)) if len(client_ids) != len(fs_result.clients): logging.error("Expected %d results from Fleetspeak; got %d instead.", len(client_ids), len(fs_result.clients)) last_contact_times = {} for fs_client in fs_result.clients: grr_id = fleetspeak_utils.FleetspeakIDToGRRID(fs_client.client_id) last_contact_times[grr_id] = fleetspeak_utils.TSToRDFDatetime( fs_client.last_contact_time) return last_contact_times
def UpdateClientsFromFleetspeak(clients): """Updates ApiClient records to include info from Fleetspeak.""" if not fleetspeak_connector.CONN or not fleetspeak_connector.CONN.outgoing: # FS not configured, or an outgoing connection is otherwise unavailable. return id_map = {} for client in clients: if client.fleetspeak_enabled: id_map[fleetspeak_utils.GRRIDToFleetspeakID(client.client_id)] = client if not id_map: return res = fleetspeak_connector.CONN.outgoing.ListClients( admin_pb2.ListClientsRequest(client_ids=list(iterkeys(id_map)))) for read in res.clients: api_client = id_map[read.client_id] api_client.last_seen_at = fleetspeak_utils.TSToRDFDatetime( read.last_contact_time) api_client.last_clock = fleetspeak_utils.TSToRDFDatetime(read.last_clock)
def Run(self): if not fleetspeak_connector.CONN or not fleetspeak_connector.CONN.outgoing: # Nothing to do if Fleetspeak is not enabled. self.Log("Fleetspeak has not been initialized. Will do nothing.") return if not data_store.RelationalDBWriteEnabled(): raise NotImplementedError( "Cronjob does not support the legacy datastore.") age_threshold = config.CONFIG["Server.fleetspeak_last_ping_threshold"] max_last_ping = rdfvalue.RDFDatetime.Now() - age_threshold last_pings = data_store.REL_DB.ReadClientLastPings( max_last_ping=max_last_ping, fleetspeak_enabled=True) num_clients_updated = 0 batch_size = config.CONFIG["Server.fleetspeak_list_clients_batch_size"] for client_ids in collection.Batch(iterkeys(last_pings), batch_size): fs_ids = [ fleetspeak_utils.GRRIDToFleetspeakID(i) for i in client_ids ] request_start = rdfvalue.RDFDatetime.Now() fs_result = fleetspeak_connector.CONN.outgoing.ListClients( admin_pb2.ListClientsRequest(client_ids=fs_ids)) latency = rdfvalue.RDFDatetime.Now() - request_start logging.info("Fleetspeak ListClients() took %s.", latency) stats_collector_instance.Get().RecordEvent( "fleetspeak_last_ping_latency_millis", latency.milliseconds) for fs_client in fs_result.clients: grr_id = fleetspeak_utils.FleetspeakIDToGRRID( fs_client.client_id) new_last_ping = fleetspeak_utils.TSToRDFDatetime( fs_client.last_contact_time) if last_pings[grr_id] is None or last_pings[ grr_id] < new_last_ping: data_store.REL_DB.WriteClientMetadata( grr_id, last_ping=new_last_ping) num_clients_updated += 1 self.Log("Updated timestamps for %d clients.", num_clients_updated)