@Override
  @DB
  public boolean revokeSecurityGroupIngress(RevokeSecurityGroupIngressCmd cmd) {
    // input validation
    Account caller = UserContext.current().getCaller();
    Long id = cmd.getId();

    IngressRuleVO rule = _ingressRuleDao.findById(id);
    if (rule == null) {
      s_logger.debug("Unable to find ingress rule with id " + id);
      throw new InvalidParameterValueException("Unable to find ingress rule with id " + id);
    }

    // Check permissions
    SecurityGroup securityGroup = _securityGroupDao.findById(rule.getSecurityGroupId());
    _accountMgr.checkAccess(caller, null, securityGroup);

    SecurityGroupVO groupHandle = null;
    final Transaction txn = Transaction.currentTxn();

    try {
      txn.start();
      // acquire lock on parent group (preserving this logic)
      groupHandle = _securityGroupDao.acquireInLockTable(rule.getSecurityGroupId());
      if (groupHandle == null) {
        s_logger.warn("Could not acquire lock on security group id: " + rule.getSecurityGroupId());
        return false;
      }

      _ingressRuleDao.remove(id);
      s_logger.debug("revokeSecurityGroupIngress succeeded for ingress rule id: " + id);

      final ArrayList<Long> affectedVms = new ArrayList<Long>();
      affectedVms.addAll(_securityGroupVMMapDao.listVmIdsBySecurityGroup(groupHandle.getId()));
      scheduleRulesetUpdateToHosts(affectedVms, true, null);

      return true;
    } catch (Exception e) {
      s_logger.warn("Exception caught when deleting ingress rules ", e);
      throw new CloudRuntimeException("Exception caught when deleting ingress rules", e);
    } finally {
      if (groupHandle != null) {
        _securityGroupDao.releaseFromLockTable(groupHandle.getId());
      }
      txn.commit();
    }
  }
 protected List<Long> getAffectedVmsForVmStop(VMInstanceVO vm) {
   List<Long> affectedVms = new ArrayList<Long>();
   List<SecurityGroupVMMapVO> groupsForVm = _securityGroupVMMapDao.listByInstanceId(vm.getId());
   // For each group, find the ingress rules that allow the group
   for (SecurityGroupVMMapVO mapVO : groupsForVm) { // FIXME: use custom sql in the dao
     List<IngressRuleVO> allowingRules =
         _ingressRuleDao.listByAllowedSecurityGroupId(mapVO.getSecurityGroupId());
     // For each ingress rule that allows a group that the vm belongs to, find the group it belongs
     // to
     affectedVms.addAll(getAffectedVmsForIngressRules(allowingRules));
   }
   return affectedVms;
 }
  @DB
  @Override
  @ActionEvent(
      eventType = EventTypes.EVENT_SECURITY_GROUP_DELETE,
      eventDescription = "deleting security group")
  public boolean deleteSecurityGroup(DeleteSecurityGroupCmd cmd) throws ResourceInUseException {
    Long groupId = cmd.getId();
    Account caller = UserContext.current().getCaller();

    SecurityGroupVO group = _securityGroupDao.findById(groupId);
    if (group == null) {
      throw new InvalidParameterValueException(
          "Unable to find network group: " + groupId + "; failed to delete group.");
    }

    // check permissions
    _accountMgr.checkAccess(caller, null, group);

    final Transaction txn = Transaction.currentTxn();
    txn.start();

    group = _securityGroupDao.lockRow(groupId, true);
    if (group == null) {
      throw new InvalidParameterValueException("Unable to find security group by id " + groupId);
    }

    if (group.getName().equalsIgnoreCase(SecurityGroupManager.DEFAULT_GROUP_NAME)) {
      throw new InvalidParameterValueException("The network group default is reserved");
    }

    List<IngressRuleVO> allowingRules = _ingressRuleDao.listByAllowedSecurityGroupId(groupId);
    List<SecurityGroupVMMapVO> securityGroupVmMap =
        _securityGroupVMMapDao.listBySecurityGroup(groupId);
    if (!allowingRules.isEmpty()) {
      throw new ResourceInUseException(
          "Cannot delete group when there are ingress rules that allow this group");
    } else if (!securityGroupVmMap.isEmpty()) {
      throw new ResourceInUseException("Cannot delete group when it's in use by virtual machines");
    }

    _securityGroupDao.expunge(groupId);
    txn.commit();

    s_logger.debug("Deleted security group id=" + groupId);

    return true;
  }
  protected Map<PortAndProto, Set<String>> generateRulesForVM(Long userVmId) {

    Map<PortAndProto, Set<String>> allowed = new TreeMap<PortAndProto, Set<String>>();

    List<SecurityGroupVMMapVO> groupsForVm = _securityGroupVMMapDao.listByInstanceId(userVmId);
    for (SecurityGroupVMMapVO mapVO : groupsForVm) {
      List<IngressRuleVO> rules = _ingressRuleDao.listBySecurityGroupId(mapVO.getSecurityGroupId());
      for (IngressRuleVO rule : rules) {
        PortAndProto portAndProto =
            new PortAndProto(rule.getProtocol(), rule.getStartPort(), rule.getEndPort());
        Set<String> cidrs = allowed.get(portAndProto);
        if (cidrs == null) {
          cidrs = new TreeSet<String>(new CidrComparator());
        }
        if (rule.getAllowedNetworkId() != null) {
          List<SecurityGroupVMMapVO> allowedInstances =
              _securityGroupVMMapDao.listBySecurityGroup(rule.getAllowedNetworkId(), State.Running);
          for (SecurityGroupVMMapVO ngmapVO : allowedInstances) {
            Nic defaultNic = _networkMgr.getDefaultNic(ngmapVO.getInstanceId());
            if (defaultNic != null) {
              String cidr = defaultNic.getIp4Address();
              cidr = cidr + "/32";
              cidrs.add(cidr);
            }
          }
        } else if (rule.getAllowedSourceIpCidr() != null) {
          cidrs.add(rule.getAllowedSourceIpCidr());
        }
        if (cidrs.size() > 0) {
          allowed.put(portAndProto, cidrs);
        }
      }
    }

    return allowed;
  }
  @Override
  @DB
  @SuppressWarnings("rawtypes")
  public List<IngressRuleVO> authorizeSecurityGroupIngress(AuthorizeSecurityGroupIngressCmd cmd) {
    Long securityGroupId = cmd.getSecurityGroupId();
    String protocol = cmd.getProtocol();
    Integer startPort = cmd.getStartPort();
    Integer endPort = cmd.getEndPort();
    Integer icmpType = cmd.getIcmpType();
    Integer icmpCode = cmd.getIcmpCode();
    List<String> cidrList = cmd.getCidrList();
    Map groupList = cmd.getUserSecurityGroupList();
    Integer startPortOrType = null;
    Integer endPortOrCode = null;

    // Validate parameters
    SecurityGroup securityGroup = _securityGroupDao.findById(securityGroupId);
    if (securityGroup == null) {
      throw new InvalidParameterValueException(
          "Unable to find security group by id " + securityGroupId);
    }

    if (cidrList == null && groupList == null) {
      throw new InvalidParameterValueException(
          "At least one cidr or at least one security group needs to be specified");
    }

    Account caller = UserContext.current().getCaller();
    Account owner = _accountMgr.getAccount(securityGroup.getAccountId());

    if (owner == null) {
      throw new InvalidParameterValueException(
          "Unable to find security group owner by id=" + securityGroup.getAccountId());
    }

    // Verify permissions
    _accountMgr.checkAccess(caller, null, securityGroup);
    Long domainId = owner.getDomainId();

    if (protocol == null) {
      protocol = NetUtils.ALL_PROTO;
    }

    if (!NetUtils.isValidSecurityGroupProto(protocol)) {
      throw new InvalidParameterValueException("Invalid protocol " + protocol);
    }
    if ("icmp".equalsIgnoreCase(protocol)) {
      if ((icmpType == null) || (icmpCode == null)) {
        throw new InvalidParameterValueException(
            "Invalid ICMP type/code specified, icmpType = "
                + icmpType
                + ", icmpCode = "
                + icmpCode);
      }
      if (icmpType == -1 && icmpCode != -1) {
        throw new InvalidParameterValueException("Invalid icmp type range");
      }
      if (icmpCode > 255) {
        throw new InvalidParameterValueException("Invalid icmp code ");
      }
      startPortOrType = icmpType;
      endPortOrCode = icmpCode;
    } else if (protocol.equals(NetUtils.ALL_PROTO)) {
      if ((startPort != null) || (endPort != null)) {
        throw new InvalidParameterValueException(
            "Cannot specify startPort or endPort without specifying protocol");
      }
      startPortOrType = 0;
      endPortOrCode = 0;
    } else {
      if ((startPort == null) || (endPort == null)) {
        throw new InvalidParameterValueException(
            "Invalid port range specified, startPort = " + startPort + ", endPort = " + endPort);
      }
      if (startPort == 0 && endPort == 0) {
        endPort = 65535;
      }
      if (startPort > endPort) {
        throw new InvalidParameterValueException("Invalid port range " + startPort + ":" + endPort);
      }
      if (startPort > 65535 || endPort > 65535 || startPort < -1 || endPort < -1) {
        throw new InvalidParameterValueException(
            "Invalid port numbers " + startPort + ":" + endPort);
      }

      if (startPort < 0 || endPort < 0) {
        throw new InvalidParameterValueException("Invalid port range " + startPort + ":" + endPort);
      }
      startPortOrType = startPort;
      endPortOrCode = endPort;
    }

    protocol = protocol.toLowerCase();

    List<SecurityGroupVO> authorizedGroups = new ArrayList<SecurityGroupVO>();
    if (groupList != null) {
      Collection userGroupCollection = groupList.values();
      Iterator iter = userGroupCollection.iterator();
      while (iter.hasNext()) {
        HashMap userGroup = (HashMap) iter.next();
        String group = (String) userGroup.get("group");
        String authorizedAccountName = (String) userGroup.get("account");

        if ((group == null) || (authorizedAccountName == null)) {
          throw new InvalidParameterValueException(
              "Invalid user group specified, fields 'group' and 'account' cannot be null, please specify groups in the form:  userGroupList[0].group=XXX&userGroupList[0].account=YYY");
        }

        Account authorizedAccount = _accountDao.findActiveAccount(authorizedAccountName, domainId);
        if (authorizedAccount == null) {
          throw new InvalidParameterValueException(
              "Nonexistent account: "
                  + authorizedAccountName
                  + " when trying to authorize ingress for "
                  + securityGroupId
                  + ":"
                  + protocol
                  + ":"
                  + startPortOrType
                  + ":"
                  + endPortOrCode);
        }

        SecurityGroupVO groupVO =
            _securityGroupDao.findByAccountAndName(authorizedAccount.getId(), group);
        if (groupVO == null) {
          throw new InvalidParameterValueException(
              "Nonexistent group "
                  + group
                  + " for account "
                  + authorizedAccountName
                  + "/"
                  + domainId
                  + " is given, unable to authorize ingress.");
        }

        // Check permissions
        if (domainId != groupVO.getDomainId()) {
          throw new PermissionDeniedException(
              "Can't add security group id="
                  + groupVO.getDomainId()
                  + " as it belongs to different domain");
        }

        authorizedGroups.add(groupVO);
      }
    }

    final Transaction txn = Transaction.currentTxn();
    final Set<SecurityGroupVO> authorizedGroups2 =
        new TreeSet<SecurityGroupVO>(new SecurityGroupVOComparator());

    authorizedGroups2.addAll(authorizedGroups); // Ensure we don't re-lock the same row
    txn.start();

    // Prevents other threads/management servers from creating duplicate ingress rules
    securityGroup = _securityGroupDao.acquireInLockTable(securityGroupId);
    if (securityGroup == null) {
      s_logger.warn("Could not acquire lock on network security group: id= " + securityGroupId);
      return null;
    }
    List<IngressRuleVO> newRules = new ArrayList<IngressRuleVO>();
    try {
      for (final SecurityGroupVO ngVO : authorizedGroups2) {
        final Long ngId = ngVO.getId();
        // Don't delete the referenced group from under us
        if (ngVO.getId() != securityGroup.getId()) {
          final SecurityGroupVO tmpGrp = _securityGroupDao.lockRow(ngId, false);
          if (tmpGrp == null) {
            s_logger.warn("Failed to acquire lock on security group: " + ngId);
            txn.rollback();
            return null;
          }
        }
        IngressRuleVO ingressRule =
            _ingressRuleDao.findByProtoPortsAndAllowedGroupId(
                securityGroup.getId(), protocol, startPortOrType, endPortOrCode, ngVO.getId());
        if (ingressRule != null) {
          continue; // rule already exists.
        }
        ingressRule =
            new IngressRuleVO(
                securityGroup.getId(), startPortOrType, endPortOrCode, protocol, ngVO.getId());
        ingressRule = _ingressRuleDao.persist(ingressRule);
        newRules.add(ingressRule);
      }
      if (cidrList != null) {
        for (String cidr : cidrList) {
          IngressRuleVO ingressRule =
              _ingressRuleDao.findByProtoPortsAndCidr(
                  securityGroup.getId(), protocol, startPortOrType, endPortOrCode, cidr);
          if (ingressRule != null) {
            continue;
          }
          ingressRule =
              new IngressRuleVO(
                  securityGroup.getId(), startPortOrType, endPortOrCode, protocol, cidr);
          ingressRule = _ingressRuleDao.persist(ingressRule);
          newRules.add(ingressRule);
        }
      }
      if (s_logger.isDebugEnabled()) {
        s_logger.debug(
            "Added " + newRules.size() + " rules to security group " + securityGroup.getName());
      }
      txn.commit();
      final ArrayList<Long> affectedVms = new ArrayList<Long>();
      affectedVms.addAll(_securityGroupVMMapDao.listVmIdsBySecurityGroup(securityGroup.getId()));
      scheduleRulesetUpdateToHosts(affectedVms, true, null);
      return newRules;
    } catch (Exception e) {
      s_logger.warn("Exception caught when adding ingress rules ", e);
      throw new CloudRuntimeException("Exception caught when adding ingress rules", e);
    } finally {
      if (securityGroup != null) {
        _securityGroupDao.releaseFromLockTable(securityGroup.getId());
      }
    }
  }