@Override
 public boolean processDisconnect(long agentId, Status state) {
   if (_workTracker != null) {
     _workTracker.processDisconnect(agentId);
   }
   return true;
 }
 @Override
 public boolean processTimeout(long agentId, long seq) {
   if (_workTracker != null) {
     _workTracker.processTimeout(agentId, seq);
   }
   return true;
 }
  @Override
  public boolean processAnswers(long agentId, long seq, Answer[] answers) {
    List<Long> affectedVms = new ArrayList<Long>();
    int commandNum = 0;
    for (Answer ans : answers) {
      if (ans instanceof SecurityGroupRuleAnswer) {
        SecurityGroupRuleAnswer ruleAnswer = (SecurityGroupRuleAnswer) ans;
        if (ans.getResult()) {
          s_logger.debug(
              "Successfully programmed rule " + ruleAnswer.toString() + " into host " + agentId);
          _workDao.updateStep(ruleAnswer.getVmId(), ruleAnswer.getLogSequenceNumber(), Step.Done);
          recordSuccess(ruleAnswer.getVmId());
        } else {
          _workDao.updateStep(ruleAnswer.getVmId(), ruleAnswer.getLogSequenceNumber(), Step.Error);
          ;
          s_logger.debug(
              "Failed to program rule "
                  + ruleAnswer.toString()
                  + " into host "
                  + agentId
                  + " due to "
                  + ruleAnswer.getDetails()
                  + " and updated  jobs");
          if (ruleAnswer.getReason() == FailureReason.CANNOT_BRIDGE_FIREWALL) {
            s_logger.debug(
                "Not retrying security group rules for vm "
                    + ruleAnswer.getVmId()
                    + " on failure since host "
                    + agentId
                    + " cannot do bridge firewalling");
          } else if (ruleAnswer.getReason() == FailureReason.PROGRAMMING_FAILED) {
            if (checkShouldRetryOnFailure(ruleAnswer.getVmId())) {
              s_logger.debug(
                  "Retrying security group rules on failure for vm " + ruleAnswer.getVmId());
              affectedVms.add(ruleAnswer.getVmId());
            } else {
              s_logger.debug(
                  "Not retrying security group rules for vm "
                      + ruleAnswer.getVmId()
                      + " on failure: too many retries");
            }
          }
        }
        commandNum++;
        if (_workTracker != null) _workTracker.processAnswers(agentId, seq, answers);
      }
    }

    if (affectedVms.size() > 0) {
      _securityGroupManager.scheduleRulesetUpdateToHosts(affectedVms, false, new Long(10 * 1000l));
    }

    return true;
  }
  @Override
  public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) {
    if (s_logger.isInfoEnabled()) s_logger.info("Received a host startup notification");

    if (cmd instanceof StartupRoutingCommand) {
      // if (Boolean.toString(true).equals(host.getDetail("can_bridge_firewall"))) {
      try {
        int interval =
            MIN_TIME_BETWEEN_CLEANUPS + _cleanupRandom.nextInt(MIN_TIME_BETWEEN_CLEANUPS / 2);
        CleanupNetworkRulesCmd cleanupCmd = new CleanupNetworkRulesCmd(interval);
        Commands c = new Commands(cleanupCmd);
        _agentMgr.send(host.getId(), c, this);
        if (s_logger.isInfoEnabled())
          s_logger.info("Scheduled network rules cleanup, interval=" + cleanupCmd.getInterval());
      } catch (AgentUnavailableException e) {
        // usually hypervisors that do not understand sec group rules.
        s_logger.debug("Unable to schedule network rules cleanup for host " + host.getId(), e);
      }
      if (_workTracker != null) {
        _workTracker.processConnect(host.getId());
      }
    }
  }