@Override
  @DB
  public void destroyRemoteAccessVpn(long ipId, Account caller)
      throws ResourceUnavailableException {
    RemoteAccessVpnVO vpn = _remoteAccessVpnDao.findById(ipId);
    if (vpn == null) {
      s_logger.debug("vpn id=" + ipId + " does not exists ");
      return;
    }

    _accountMgr.checkAccess(caller, null, true, vpn);

    Network network = _networkMgr.getNetwork(vpn.getNetworkId());

    vpn.setState(RemoteAccessVpn.State.Removed);
    _remoteAccessVpnDao.update(vpn.getServerAddressId(), vpn);

    boolean success = false;
    try {
      for (RemoteAccessVPNServiceProvider element : _vpnServiceProviders) {
        if (element.stopVpn(network, vpn)) {
          success = true;
          break;
        }
      }
    } finally {
      if (success) {
        // Cleanup corresponding ports
        List<? extends FirewallRule> vpnFwRules = _rulesDao.listByIpAndPurpose(ipId, Purpose.Vpn);
        Transaction txn = Transaction.currentTxn();

        boolean applyFirewall = false;
        List<FirewallRuleVO> fwRules = new ArrayList<FirewallRuleVO>();
        // if related firewall rule is created for the first vpn port, it would be created for the 2
        // other ports as well, so need to cleanup the backend
        if (_rulesDao.findByRelatedId(vpnFwRules.get(0).getId()) != null) {
          applyFirewall = true;
        }

        if (applyFirewall) {
          txn.start();

          for (FirewallRule vpnFwRule : vpnFwRules) {
            // don't apply on the backend yet; send all 3 rules in a banch
            _firewallMgr.revokeRelatedFirewallRule(vpnFwRule.getId(), false);
            fwRules.add(_rulesDao.findByRelatedId(vpnFwRule.getId()));
          }

          s_logger.debug(
              "Marked "
                  + fwRules.size()
                  + " firewall rules as Revoked as a part of disable remote access vpn");

          txn.commit();

          // now apply vpn rules on the backend
          s_logger.debug(
              "Reapplying firewall rules for ip id="
                  + ipId
                  + " as a part of disable remote access vpn");
          success = _firewallMgr.applyIngressFirewallRules(ipId, caller);
        }

        if (success) {
          try {
            txn.start();
            _remoteAccessVpnDao.remove(ipId);
            // Stop billing of VPN users when VPN is removed. VPN_User_ADD events will be generated
            // when VPN is created again
            List<VpnUserVO> vpnUsers = _vpnUsersDao.listByAccount(vpn.getAccountId());
            for (VpnUserVO user : vpnUsers) {
              // VPN_USER_REMOVE event is already generated for users in Revoke state
              if (user.getState() != VpnUser.State.Revoke) {
                UsageEventUtils.publishUsageEvent(
                    EventTypes.EVENT_VPN_USER_REMOVE,
                    user.getAccountId(),
                    0,
                    user.getId(),
                    user.getUsername(),
                    user.getClass().getName(),
                    user.getUuid());
              }
            }
            if (vpnFwRules != null) {
              for (FirewallRule vpnFwRule : vpnFwRules) {
                _rulesDao.remove(vpnFwRule.getId());
                s_logger.debug(
                    "Successfully removed firewall rule with ip id="
                        + vpnFwRule.getSourceIpAddressId()
                        + " and port "
                        + vpnFwRule.getSourcePortStart()
                        + " as a part of vpn cleanup");
              }
            }
            txn.commit();
          } catch (Exception ex) {
            txn.rollback();
            s_logger.warn("Unable to release the three vpn ports from the firewall rules", ex);
          }
        }
      }
    }
  }
  @DB
  public boolean deleteLoadBalancerRule(
      long loadBalancerId, boolean apply, Account caller, long callerUserId) {
    LoadBalancerVO lb = _lbDao.findById(loadBalancerId);
    Transaction txn = Transaction.currentTxn();
    boolean generateUsageEvent = false;
    boolean success = true;

    txn.start();
    if (lb.getState() == FirewallRule.State.Staged) {
      if (s_logger.isDebugEnabled()) {
        s_logger.debug("Found a rule that is still in stage state so just removing it: " + lb);
      }
      generateUsageEvent = true;
    } else if (lb.getState() == FirewallRule.State.Add
        || lb.getState() == FirewallRule.State.Active) {
      lb.setState(FirewallRule.State.Revoke);
      _lbDao.persist(lb);
      generateUsageEvent = true;
    }

    List<LoadBalancerVMMapVO> maps = _lb2VmMapDao.listByLoadBalancerId(loadBalancerId);
    if (maps != null) {
      for (LoadBalancerVMMapVO map : maps) {
        map.setRevoke(true);
        _lb2VmMapDao.persist(map);
        s_logger.debug(
            "Set load balancer rule for revoke: rule id "
                + loadBalancerId
                + ", vmId "
                + map.getInstanceId());
      }
    }

    if (generateUsageEvent) {
      // Generate usage event right after all rules were marked for revoke
      UsageEventVO usageEvent =
          new UsageEventVO(
              EventTypes.EVENT_LOAD_BALANCER_DELETE, lb.getAccountId(), 0, lb.getId(), null);
      _usageEventDao.persist(usageEvent);
    }

    txn.commit();

    if (apply) {
      try {
        if (!applyLoadBalancerConfig(loadBalancerId)) {
          s_logger.warn("Unable to apply the load balancer config");
          return false;
        }
      } catch (ResourceUnavailableException e) {
        s_logger.warn(
            "Unable to apply the load balancer config because resource is unavaliable.", e);
        return false;
      }
    }

    FirewallRuleVO relatedRule = _firewallDao.findByRelatedId(lb.getId());
    if (relatedRule != null) {
      s_logger.warn(
          "Unable to remove firewall rule id="
              + lb.getId()
              + " as it has related firewall rule id="
              + relatedRule.getId()
              + "; leaving it in Revoke state");
      success = false;
    } else {
      _firewallDao.remove(lb.getId());
    }

    _elbMgr.handleDeleteLoadBalancerRule(lb, callerUserId, caller);
    if (success) {
      s_logger.debug("Load balancer with id " + lb.getId() + " is removed successfully");
    }

    return success;
  }
  @Override
  public void removeRule(FirewallRule rule) {

    // remove the rule
    _firewallDao.remove(rule.getId());
  }