Method which evaluates all attack work.

    In a loop this method queries not completed attack work, picks one
    attack work and runs it.

def run_attacks(self):
    """Method which evaluates all attack work.

    In a loop this method queries not completed attack work, picks one
    attack work and runs it.
    """
    logging.info('******** Start evaluation of attacks ********')
    prev_submission_id = None
    while True:
      # wait until work is available
      self.attack_work.read_all_from_datastore()
      if not self.attack_work.work:
        logging.info('Work is not populated, waiting...')
        time.sleep(SLEEP_TIME)
        continue
      if self.attack_work.is_all_work_competed():
        logging.info('All attack work completed.')
        break
      # download all attacks data and dataset
      self.fetch_attacks_data()
      # pick piece of work
      work_id = self.attack_work.try_pick_piece_of_work(
          self.worker_id, submission_id=prev_submission_id)
      if not work_id:
        logging.info('Failed to pick work, waiting...')
        time.sleep(SLEEP_TIME_SHORT)
        continue
      logging.info('Selected work_id: %s', work_id)
      # execute work
      try:
        elapsed_time_sec, prev_submission_id = self.run_attack_work(work_id)
        logging.info('Work %s is done', work_id)
        # indicate that work is completed
        is_work_update = self.attack_work.update_work_as_completed(
            self.worker_id, work_id,
            other_values={'elapsed_time': elapsed_time_sec})
      except WorkerError as e:
        logging.info('Failed to run work:\n%s', str(e))
        is_work_update = self.attack_work.update_work_as_completed(
            self.worker_id, work_id, error=str(e))
      if not is_work_update:
        logging.warning('Can''t update work "%s" as completed by worker %d',
                        work_id, self.worker_id)
    logging.info('******** Finished evaluation of attacks ********')