Пример #1
0
  def WriteClientMessages(self, messages):
    """Writes messages that should go to the client to the db."""
    client_ids = [db_utils.ClientIdFromGrrMessage(msg) for msg in messages]
    for client_id in client_ids:
      if client_id not in self.metadatas:
        raise db.AtLeastOneUnknownClientError(client_ids=client_ids)

    for m in messages:
      client_id = db_utils.ClientIdFromGrrMessage(m)
      self.client_messages.setdefault(client_id, {})[m.task_id] = m
Пример #2
0
  def WriteClientMessages(self, messages, cursor=None):
    """Writes messages that should go to the client to the db."""

    query = ("INSERT IGNORE INTO client_messages "
             "(client_id, message_id, timestamp, message) "
             "VALUES %s ON DUPLICATE KEY UPDATE "
             "timestamp=VALUES(timestamp), message=VALUES(message)")
    now = mysql_utils.RDFDatetimeToMysqlString(rdfvalue.RDFDatetime.Now())

    client_ids = set()

    value_templates = []
    args = []
    for m in messages:
      cid = db_utils.ClientIdFromGrrMessage(m)
      client_ids.add(cid)
      client_id_int = mysql_utils.ClientIDToInt(cid)
      args.extend([client_id_int, m.task_id, now, m.SerializeToString()])
      value_templates.append("(%s, %s, %s, %s)")

    query %= ",".join(value_templates)
    try:
      cursor.execute(query, args)
    except MySQLdb.IntegrityError as e:
      raise db.AtLeastOneUnknownClientError(client_ids=client_ids, cause=e)
Пример #3
0
    def LeaseClientMessages(self,
                            client_id,
                            lease_time=None,
                            limit=sys.maxsize):
        """Leases available client messages for the client with the given id."""
        leased_messages = []

        now = rdfvalue.RDFDatetime.Now()
        expiration_time = now + lease_time
        process_id_str = utils.ProcessIdString()

        leases = self.client_message_leases
        for msgs_by_id in itervalues(self.client_messages):
            for msg in sorted(itervalues(msgs_by_id), key=lambda m: m.task_id):
                if db_utils.ClientIdFromGrrMessage(msg) != client_id:
                    continue

                existing_lease = leases.get(msg.task_id)
                if not existing_lease or existing_lease[0] < now:
                    leases[msg.task_id] = (expiration_time, process_id_str)
                    msg.leased_until = expiration_time
                    msg.leased_by = process_id_str
                    leased_messages.append(msg)
                    if len(leased_messages) >= limit:
                        break

        return leased_messages
Пример #4
0
  def LeaseClientMessages(self, client_id, lease_time=None, limit=sys.maxsize):
    """Leases available client messages for the client with the given id."""
    leased_messages = []

    now = rdfvalue.RDFDatetime.Now()
    expiration_time = now + lease_time
    process_id_str = utils.ProcessIdString()

    leases = self.client_message_leases
    for msgs_by_id in itervalues(self.client_messages):
      for msg in sorted(itervalues(msgs_by_id), key=lambda m: m.task_id):
        if db_utils.ClientIdFromGrrMessage(msg) != client_id:
          continue

        existing_lease = leases.get(msg.task_id)
        if not existing_lease or existing_lease[0] < now:
          if existing_lease:
            lease_count = existing_lease[-1] + 1
            # >= comparison since this check happens before the lease.
            if lease_count >= db.Database.CLIENT_MESSAGES_TTL:
              self._DeleteClientMessage(client_id, msg.task_id)
              continue
            leases[msg.task_id] = (expiration_time, process_id_str, lease_count)
          else:
            leases[msg.task_id] = (expiration_time, process_id_str, 0)

          msg.leased_until = expiration_time
          msg.leased_by = process_id_str
          leased_messages.append(msg)
          if len(leased_messages) >= limit:
            break

    return leased_messages
Пример #5
0
  def DeleteClientMessages(self, messages):
    """Deletes a list of client messages from the db."""
    to_delete = []
    for m in messages:
      client_id = db_utils.ClientIdFromGrrMessage(m)
      to_delete.append((client_id, m.task_id))

    if len(set(to_delete)) != len(to_delete):
      raise ValueError(
          "Received multiple copies of the same message to delete.")

    for client_id, task_id in to_delete:
      self._DeleteClientMessage(client_id, task_id)
Пример #6
0
  def ReadClientMessages(self, client_id):
    """Reads all client messages available for a given client_id."""
    res = []
    for msgs_by_id in itervalues(self.client_messages):
      for orig_msg in sorted(itervalues(msgs_by_id), key=lambda m: m.task_id):
        if db_utils.ClientIdFromGrrMessage(orig_msg) != client_id:
          continue
        msg = orig_msg.Copy()
        current_lease = self.client_message_leases.get(msg.task_id)
        if current_lease:
          msg.leased_until, msg.leased_by = current_lease
        res.append(msg)

    return res
Пример #7
0
  def DeleteClientMessages(self, messages, cursor=None):
    """Deletes a list of client messages from the db."""
    if not messages:
      return

    to_delete = []
    for m in messages:
      to_delete.append((db_utils.ClientIdFromGrrMessage(m), m.task_id))

    if len(set(to_delete)) != len(to_delete):
      raise ValueError(
          "Received multiple copies of the same message to delete.")

    self._DeleteClientMessages(to_delete, cursor=cursor)
Пример #8
0
    def DeleteClientMessages(self, messages):
        """Deletes a list of client messages from the db."""
        to_delete = []
        for m in messages:
            client_id = db_utils.ClientIdFromGrrMessage(m)
            to_delete.append((client_id, m.task_id))

        if len(set(to_delete)) != len(to_delete):
            raise ValueError(
                "Received multiple copies of the same message to delete.")

        for client_id, task_id in to_delete:
            tasks = self.client_messages.get(client_id)
            if not tasks or task_id not in tasks:
                # TODO(amoser): Once new flows are in, reevaluate if we can raise on
                # deletion request for unknown messages.
                continue
            del tasks[task_id]
            if task_id in self.client_message_leases:
                del self.client_message_leases[task_id]
Пример #9
0
  def DeleteClientMessages(self, messages, cursor=None):
    """Deletes a list of client messages from the db."""
    if not messages:
      return

    args = []
    conditions = ["(client_id=%s and message_id=%s)"] * len(messages)
    query = "DELETE FROM client_messages WHERE " + " OR ".join(conditions)
    to_delete = []
    for m in messages:
      client_id = mysql_utils.ClientIDToInt(db_utils.ClientIdFromGrrMessage(m))
      to_delete.append((client_id, m.task_id))

    if len(set(to_delete)) != len(to_delete):
      raise ValueError(
          "Received multiple copies of the same message to delete.")

    for client_id, task_id in to_delete:
      args.append(client_id)
      args.append(task_id)
    cursor.execute(query, args)
Пример #10
0
 def WriteClientMessages(self, messages):
     """Writes messages that should go to the client to the db."""
     for m in messages:
         client_id = db_utils.ClientIdFromGrrMessage(m)
         self.client_messages.setdefault(client_id, {})[m.task_id] = m