@Override
  public String getSecurityGroupsNamesForVm(long vmId) {
    try {
      List<SecurityGroupVMMapVO> networkGroupsToVmMap =
          _securityGroupVMMapDao.listByInstanceId(vmId);
      int size = 0;
      int j = 0;
      StringBuilder networkGroupNames = new StringBuilder();

      if (networkGroupsToVmMap != null) {
        size = networkGroupsToVmMap.size();

        for (SecurityGroupVMMapVO nG : networkGroupsToVmMap) {
          // get the group id and look up for the group name
          SecurityGroupVO currentNetworkGroup = _securityGroupDao.findById(nG.getSecurityGroupId());
          networkGroupNames.append(currentNetworkGroup.getName());

          if (j < (size - 1)) {
            networkGroupNames.append(",");
            j++;
          }
        }
      }

      return networkGroupNames.toString();
    } catch (Exception e) {
      s_logger.warn("Error trying to get network groups for a vm: " + e);
      return null;
    }
  }
  @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();
    }
  }
  @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;
  }
 private List<SecurityGroupRulesVO> listSecurityGroupRulesByVM(long vmId) {
   List<SecurityGroupRulesVO> results = new ArrayList<SecurityGroupRulesVO>();
   List<SecurityGroupVMMapVO> networkGroupMappings = _securityGroupVMMapDao.listByInstanceId(vmId);
   if (networkGroupMappings != null) {
     for (SecurityGroupVMMapVO networkGroupMapping : networkGroupMappings) {
       SecurityGroupVO group =
           _securityGroupDao.findById(networkGroupMapping.getSecurityGroupId());
       List<SecurityGroupRulesVO> rules =
           _securityGroupRulesDao.listSecurityGroupRules(
               group.getAccountId(), networkGroupMapping.getGroupName());
       if (rules != null) {
         results.addAll(rules);
       }
     }
   }
   return results;
 }
  @Override
  @DB
  public boolean addInstanceToGroups(final Long userVmId, final List<Long> groups) {
    if (!isVmSecurityGroupEnabled(userVmId)) {
      s_logger.warn(
          "User vm " + userVmId + " is not security group enabled, can't add it to security group");
      return false;
    }
    if (groups != null && !groups.isEmpty()) {

      final Transaction txn = Transaction.currentTxn();
      txn.start();
      UserVm userVm =
          _userVMDao.acquireInLockTable(
              userVmId); // ensures that duplicate entries are not created.
      List<SecurityGroupVO> sgs = new ArrayList<SecurityGroupVO>();
      for (Long sgId : groups) {
        sgs.add(_securityGroupDao.findById(sgId));
      }
      final Set<SecurityGroupVO> uniqueGroups =
          new TreeSet<SecurityGroupVO>(new SecurityGroupVOComparator());
      uniqueGroups.addAll(sgs);
      if (userVm == null) {
        s_logger.warn("Failed to acquire lock on user vm id=" + userVmId);
      }
      try {
        for (SecurityGroupVO securityGroup : uniqueGroups) {
          // don't let the group be deleted from under us.
          SecurityGroupVO ngrpLock = _securityGroupDao.lockRow(securityGroup.getId(), false);
          if (ngrpLock == null) {
            s_logger.warn(
                "Failed to acquire lock on network group id="
                    + securityGroup.getId()
                    + " name="
                    + securityGroup.getName());
            txn.rollback();
            return false;
          }
          if (_securityGroupVMMapDao.findByVmIdGroupId(userVmId, securityGroup.getId()) == null) {
            SecurityGroupVMMapVO groupVmMapVO =
                new SecurityGroupVMMapVO(securityGroup.getId(), userVmId);
            _securityGroupVMMapDao.persist(groupVmMapVO);
          }
        }
        txn.commit();
        return true;
      } finally {
        if (userVm != null) {
          _userVMDao.releaseFromLockTable(userVmId);
        }
      }
    }
    return false;
  }
  @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());
      }
    }
  }
 @Override
 public int compare(SecurityGroupVO o1, SecurityGroupVO o2) {
   return o1.getId() == o2.getId() ? 0 : o1.getId() < o2.getId() ? -1 : 1;
 }
  @Override
  public List<SecurityGroupRulesVO> searchForSecurityGroupRules(ListSecurityGroupsCmd cmd)
      throws PermissionDeniedException, InvalidParameterValueException {
    Account caller = UserContext.current().getCaller();
    Long domainId = cmd.getDomainId();
    String accountName = cmd.getAccountName();
    Long instanceId = cmd.getVirtualMachineId();
    String securityGroup = cmd.getSecurityGroupName();
    Long id = cmd.getId();
    Long accountId = null;

    if (instanceId != null) {
      UserVmVO userVM = _userVMDao.findById(instanceId);
      if (userVM == null) {
        throw new InvalidParameterValueException(
            "Unable to list network groups for virtual machine instance "
                + instanceId
                + "; instance not found.");
      }
      _accountMgr.checkAccess(caller, null, userVM);
      return listSecurityGroupRulesByVM(instanceId.longValue());
    }

    if (_accountMgr.isAdmin(caller.getType())) {
      if (domainId != null) {
        Domain domain = _domainMgr.getDomain(domainId);
        if (domain == null) {
          throw new InvalidParameterValueException("Unable to find domain by id " + domainId);
        }
        _accountMgr.checkAccess(caller, domain);
        if (accountName != null) {
          Account account = _accountMgr.getActiveAccountByName(accountName, domainId);
          if (account == null) {
            throw new InvalidParameterValueException(
                "Unable to find account " + accountName + " in domain " + domainId);
          }
          _accountMgr.checkAccess(caller, null, account);
          accountId = account.getId();
        }
      }
    } else {
      // regular user can see only his own security groups
      accountId = caller.getId();
    }

    List<SecurityGroupRulesVO> securityRulesList = new ArrayList<SecurityGroupRulesVO>();
    Filter searchFilter =
        new Filter(SecurityGroupVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal());
    Object keyword = cmd.getKeyword();

    SearchBuilder<SecurityGroupVO> sb = _securityGroupDao.createSearchBuilder();
    sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
    sb.and("accountId", sb.entity().getAccountId(), SearchCriteria.Op.EQ);
    sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ);
    sb.and("domainId", sb.entity().getDomainId(), SearchCriteria.Op.EQ);

    // only do a recursive domain search if the search is not limited by account or instance
    if ((accountId == null)
        && (instanceId == null)
        && (caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN)) {
      SearchBuilder<DomainVO> domainSearch = _domainDao.createSearchBuilder();
      domainSearch.and("path", domainSearch.entity().getPath(), SearchCriteria.Op.LIKE);
      sb.join(
          "domainSearch",
          domainSearch,
          sb.entity().getDomainId(),
          domainSearch.entity().getId(),
          JoinBuilder.JoinType.INNER);
    }

    SearchCriteria<SecurityGroupVO> sc = sb.create();

    if (id != null) {
      sc.setParameters("id", id);
    }

    if (securityGroup != null) {
      sc.setParameters("name", securityGroup);
    }

    if (accountId != null) {
      sc.setParameters("accountId", accountId);
    }

    // only do a recursive domain search if the search is not limited by account or instance
    if ((accountId == null)
        && (instanceId == null)
        && (caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN)) {
      DomainVO domain = _domainDao.findById(caller.getDomainId());
      sc.setJoinParameters("domainSearch", "path", domain.getPath() + "%");
    }

    if (keyword != null) {
      SearchCriteria<SecurityGroupRulesVO> ssc = _securityGroupRulesDao.createSearchCriteria();
      ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%");
      ssc.addOr("description", SearchCriteria.Op.LIKE, "%" + keyword + "%");
      sc.addAnd("name", SearchCriteria.Op.SC, ssc);
    }

    List<SecurityGroupVO> securityGroups = _securityGroupDao.search(sc, searchFilter);
    for (SecurityGroupVO group : securityGroups) {
      securityRulesList.addAll(_securityGroupRulesDao.listSecurityRulesByGroupId(group.getId()));
    }

    return securityRulesList;
  }