@Override
  @ActionEvent(
      eventType = EventTypes.EVENT_FIREWALL_CLOSE,
      eventDescription = "revoking firewall rule",
      async = true)
  public boolean revokeFirewallRulesForIp(long ipId, long userId, Account caller)
      throws ResourceUnavailableException {
    List<FirewallRule> rules = new ArrayList<FirewallRule>();

    List<FirewallRuleVO> fwRules =
        _firewallDao.listByIpAndPurposeAndNotRevoked(ipId, Purpose.Firewall);
    if (s_logger.isDebugEnabled()) {
      s_logger.debug("Releasing " + fwRules.size() + " firewall rules for ip id=" + ipId);
    }

    for (FirewallRuleVO rule : fwRules) {
      // Mark all Firewall rules as Revoke, but don't revoke them yet - we have to revoke all rules
      // for ip, no
      // need to send them one by one
      revokeFirewallRule(rule.getId(), false, caller, Account.ACCOUNT_ID_SYSTEM);
    }

    // now send everything to the backend
    List<FirewallRuleVO> rulesToApply = _firewallDao.listByIpAndPurpose(ipId, Purpose.Firewall);
    applyFirewallRules(rulesToApply, true, caller);

    // Now we check again in case more rules have been inserted.
    rules.addAll(_firewallDao.listByIpAndPurposeAndNotRevoked(ipId, Purpose.Firewall));

    if (s_logger.isDebugEnabled()) {
      s_logger.debug(
          "Successfully released firewall rules for ip id="
              + ipId
              + " and # of rules now = "
              + rules.size());
    }

    return rules.size() == 0;
  }
 @Override
 public boolean removeAllLoadBalanacersForIp(long ipId, Account caller, long callerUserId) {
   List<FirewallRuleVO> rules =
       _firewallDao.listByIpAndPurposeAndNotRevoked(ipId, Purpose.LoadBalancing);
   if (rules != null) s_logger.debug("Found " + rules.size() + " lb rules to cleanup");
   for (FirewallRule rule : rules) {
     boolean result = deleteLoadBalancerRule(rule.getId(), true, caller, callerUserId);
     if (result == false) {
       s_logger.warn("Unable to remove load balancer rule " + rule.getId());
       return false;
     }
   }
   return true;
 }
  @Override
  public void detectRulesConflict(FirewallRule newRule) throws NetworkRuleConflictException {
    List<FirewallRuleVO> rules;
    if (newRule.getSourceIpAddressId() != null) {
      rules = _firewallDao.listByIpAndPurposeAndNotRevoked(newRule.getSourceIpAddressId(), null);
      assert (rules.size() >= 1)
          : "For network rules, we now always first persist the rule and then check for "
              + "network conflicts so we should at least have one rule at this point.";
    } else {
      // fetches only firewall egress rules.
      rules =
          _firewallDao.listByNetworkPurposeTrafficTypeAndNotRevoked(
              newRule.getNetworkId(), Purpose.Firewall, newRule.getTrafficType());
      assert (rules.size() >= 1);
    }

    for (FirewallRuleVO rule : rules) {
      if (rule.getId() == newRule.getId()) {
        continue; // Skips my own rule.
      }

      boolean oneOfRulesIsFirewall =
          ((rule.getPurpose() == Purpose.Firewall || newRule.getPurpose() == Purpose.Firewall)
              && ((newRule.getPurpose() != rule.getPurpose())
                  || (!newRule.getProtocol().equalsIgnoreCase(rule.getProtocol()))));

      // if both rules are firewall and their cidrs are different, we can skip port ranges
      // verification
      boolean bothRulesFirewall =
          (rule.getPurpose() == newRule.getPurpose() && rule.getPurpose() == Purpose.Firewall);
      boolean duplicatedCidrs = false;
      if (bothRulesFirewall) {
        // Verify that the rules have different cidrs
        _firewallDao.loadSourceCidrs(rule);
        _firewallDao.loadSourceCidrs((FirewallRuleVO) newRule);

        List<String> ruleCidrList = rule.getSourceCidrList();
        List<String> newRuleCidrList = newRule.getSourceCidrList();

        if (ruleCidrList == null || newRuleCidrList == null) {
          continue;
        }

        Collection<String> similar = new HashSet<String>(ruleCidrList);
        similar.retainAll(newRuleCidrList);

        if (similar.size() > 0) {
          duplicatedCidrs = true;
        }
      }

      if (!oneOfRulesIsFirewall) {
        if (rule.getPurpose() == Purpose.StaticNat && newRule.getPurpose() != Purpose.StaticNat) {
          throw new NetworkRuleConflictException(
              "There is 1 to 1 Nat rule specified for the ip address id="
                  + newRule.getSourceIpAddressId());
        } else if (rule.getPurpose() != Purpose.StaticNat
            && newRule.getPurpose() == Purpose.StaticNat) {
          throw new NetworkRuleConflictException(
              "There is already firewall rule specified for the ip address id="
                  + newRule.getSourceIpAddressId());
        }
      }

      if (rule.getNetworkId() != newRule.getNetworkId() && rule.getState() != State.Revoke) {
        throw new NetworkRuleConflictException(
            "New rule is for a different network than what's specified in rule " + rule.getXid());
      }

      if (newRule.getProtocol().equalsIgnoreCase(NetUtils.ICMP_PROTO)
          && newRule.getProtocol().equalsIgnoreCase(rule.getProtocol())) {
        if (newRule.getIcmpCode().longValue() == rule.getIcmpCode().longValue()
            && newRule.getIcmpType().longValue() == rule.getIcmpType().longValue()
            && newRule.getProtocol().equalsIgnoreCase(rule.getProtocol())
            && duplicatedCidrs) {
          throw new InvalidParameterValueException(
              "New rule conflicts with existing rule id=" + rule.getId());
        }
      }

      boolean notNullPorts =
          (newRule.getSourcePortStart() != null
              && newRule.getSourcePortEnd() != null
              && rule.getSourcePortStart() != null
              && rule.getSourcePortEnd() != null);
      if (!notNullPorts) {
        continue;
      } else if (!oneOfRulesIsFirewall
          && !(bothRulesFirewall && !duplicatedCidrs)
          && ((rule.getSourcePortStart().intValue() <= newRule.getSourcePortStart().intValue()
                  && rule.getSourcePortEnd().intValue() >= newRule.getSourcePortStart().intValue())
              || (rule.getSourcePortStart().intValue() <= newRule.getSourcePortEnd().intValue()
                  && rule.getSourcePortEnd().intValue() >= newRule.getSourcePortEnd().intValue())
              || (newRule.getSourcePortStart().intValue() <= rule.getSourcePortStart().intValue()
                  && newRule.getSourcePortEnd().intValue() >= rule.getSourcePortStart().intValue())
              || (newRule.getSourcePortStart().intValue() <= rule.getSourcePortEnd().intValue()
                  && newRule.getSourcePortEnd().intValue()
                      >= rule.getSourcePortEnd().intValue()))) {

        // we allow port forwarding rules with the same parameters but different protocols
        boolean allowPf =
            (rule.getPurpose() == Purpose.PortForwarding
                && newRule.getPurpose() == Purpose.PortForwarding
                && !newRule.getProtocol().equalsIgnoreCase(rule.getProtocol()));
        boolean allowStaticNat =
            (rule.getPurpose() == Purpose.StaticNat
                && newRule.getPurpose() == Purpose.StaticNat
                && !newRule.getProtocol().equalsIgnoreCase(rule.getProtocol()));

        if (!(allowPf || allowStaticNat || oneOfRulesIsFirewall)) {
          throw new NetworkRuleConflictException(
              "The range specified, "
                  + newRule.getSourcePortStart()
                  + "-"
                  + newRule.getSourcePortEnd()
                  + ", conflicts with rule "
                  + rule.getId()
                  + " which has "
                  + rule.getSourcePortStart()
                  + "-"
                  + rule.getSourcePortEnd());
        }
      }
    }

    if (s_logger.isDebugEnabled()) {
      s_logger.debug(
          "No network rule conflicts detected for "
              + newRule
              + " against "
              + (rules.size() - 1)
              + " existing rules");
    }
  }