diff --git a/api/src/com/cloud/dc/DedicatedResources.java b/api/src/com/cloud/dc/DedicatedResources.java index e8e5ab3dffc..b3aea50b893 100755 --- a/api/src/com/cloud/dc/DedicatedResources.java +++ b/api/src/com/cloud/dc/DedicatedResources.java @@ -29,5 +29,5 @@ public interface DedicatedResources extends InfrastructureEntity, InternalIdenti Long getDomainId(); Long getAccountId(); String getUuid(); - + long getAffinityGroupId(); } diff --git a/api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.java b/api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.java index 59b1f47863d..e1bad930c01 100644 --- a/api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.java +++ b/api/src/org/apache/cloudstack/affinity/AffinityGroupProcessor.java @@ -72,9 +72,20 @@ public interface AffinityGroupProcessor extends Adapter { * canBeSharedDomainWide() should return true if the affinity/anti-affinity * group can be created for a domain and shared by all accounts under the * domain. - * + * * @return boolean true/false */ boolean canBeSharedDomainWide(); + /** + * subDomainAccess() should return true if the affinity/anti-affinity group + * can be created for a domain and used by the sub-domains. If true, all + * accounts under the sub-domains can see this group and use it. + * + * @return boolean true/false + */ + boolean subDomainAccess(); + + void handleDeleteGroup(AffinityGroup group); + } \ No newline at end of file diff --git a/api/src/org/apache/cloudstack/affinity/AffinityProcessorBase.java b/api/src/org/apache/cloudstack/affinity/AffinityProcessorBase.java index 0c5831a78d5..0be014eb039 100644 --- a/api/src/org/apache/cloudstack/affinity/AffinityProcessorBase.java +++ b/api/src/org/apache/cloudstack/affinity/AffinityProcessorBase.java @@ -57,4 +57,15 @@ public class AffinityProcessorBase extends AdapterBase implements AffinityGroupP public boolean canBeSharedDomainWide() { return false; } + + @Override + public void handleDeleteGroup(AffinityGroup group) { + // TODO Auto-generated method stub + return; + } + + @Override + public boolean subDomainAccess() { + return false; + } } diff --git a/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java index e50e792663e..e9aa043d9cd 100755 --- a/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java @@ -75,8 +75,9 @@ public class Upgrade410to420 implements DbUpgrade { return new File[] { new File(script) }; } - @Override - public void performDataMigration(Connection conn) { + @Override + public void performDataMigration(Connection conn) { + movePrivateZoneToDedicatedResource(conn); upgradeVmwareLabels(conn); persistLegacyZones(conn); persistVswitchConfiguration(conn); @@ -262,6 +263,126 @@ public class Upgrade410to420 implements DbUpgrade { } } + private void movePrivateZoneToDedicatedResource(Connection conn) { + + PreparedStatement pstmt = null; + ResultSet rs = null; + PreparedStatement pstmtUpdate = null; + + try { + pstmt = conn.prepareStatement("SELECT `id`, `domain_id` FROM `cloud`.`data_center` WHERE `domain_id` IS NOT NULL"); + rs = pstmt.executeQuery(); + + while (rs.next()) { + long zoneId = rs.getLong(1); + long domainId = rs.getLong(2); + long affinityGroupId; + + // create or find an affinity group for this domain of type + // 'ExplicitDedication' + + PreparedStatement pstmt2 = null; + ResultSet rs2 = null; + pstmt2 = conn + .prepareStatement("SELECT affinity_group.id FROM `cloud`.`affinity_group` INNER JOIN `cloud`.`affinity_group_domain_map` ON affinity_group.id=affinity_group_domain_map.affinity_group_id WHERE affinity_group.type = 'ExplicitDedication' AND affinity_group.acl_type = 'Domain' AND (affinity_group_domain_map.domain_id = ?)"); + pstmt2.setLong(1, domainId); + rs2 = pstmt2.executeQuery(); + if (rs2.next()) { + // group exists, use it + affinityGroupId = rs2.getLong(1); + dedicateZone(conn, zoneId, domainId, affinityGroupId); + } else { + // create new group + rs2.close(); + pstmt2.close(); + + pstmt2 = conn.prepareStatement("SELECT name FROM `cloud`.`domain` where id = ?"); + pstmt2.setLong(1, domainId); + rs2 = pstmt2.executeQuery(); + String domainName = ""; + if (rs2.next()) { + // group exists, use it + domainName = rs2.getString(1); + } + rs2.close(); + pstmt2.close(); + // create new domain level group for this domain + String type = "ExplicitDedication"; + String uuid = UUID.randomUUID().toString(); + String groupName = "DedicatedGrp-domain-" + domainName; + s_logger.debug("Adding AffinityGroup of type " + type + " for domain id " + domainId); + + String sql = "INSERT INTO `cloud`.`affinity_group` (`name`, `type`, `uuid`, `description`, `domain_id`, `account_id`, `acl_type`) VALUES (?, ?, ?, ?, 1, 1, 'Domain')"; + pstmtUpdate = conn.prepareStatement(sql); + pstmtUpdate.setString(1, groupName); + pstmtUpdate.setString(2, type); + pstmtUpdate.setString(3, uuid); + pstmtUpdate.setString(4, "dedicated resources group"); + pstmtUpdate.executeUpdate(); + pstmtUpdate.close(); + + pstmt2 = conn + .prepareStatement("SELECT affinity_group.id FROM `cloud`.`affinity_group` where uuid = ?"); + pstmt2.setString(1, uuid); + rs2 = pstmt2.executeQuery(); + if (rs2.next()) { + affinityGroupId = rs2.getLong(1); + dedicateZone(conn, zoneId, domainId, affinityGroupId); + } + } + rs2.close(); + pstmt2.close(); + } + + } catch (SQLException e) { + throw new CloudRuntimeException("Exception while Moving private zone information to dedicated resources", e); + } finally { + if (pstmtUpdate != null) { + try { + pstmtUpdate.close(); + } catch (SQLException e) { + } + } + if (rs != null) { + try { + rs.close(); + } catch (SQLException e) { + } + } + if (pstmt != null) { + try { + pstmt.close(); + } catch (SQLException e) { + } + } + + } + } + + private void dedicateZone(Connection conn, long zoneId, long domainId, long affinityGroupId) { + PreparedStatement pstmtUpdate2 = null; + try { + // create the dedicated resources entry + String sql = "INSERT INTO `cloud`.`dedicated_resources` (`uuid`,`data_center_id`, `domain_id`, `affinity_group_id`) VALUES (?, ?, ?, ?)"; + pstmtUpdate2 = conn.prepareStatement(sql); + pstmtUpdate2.setString(1, UUID.randomUUID().toString()); + pstmtUpdate2.setLong(2, zoneId); + pstmtUpdate2.setLong(3, domainId); + pstmtUpdate2.setLong(4, affinityGroupId); + pstmtUpdate2.executeUpdate(); + pstmtUpdate2.close(); + } catch (SQLException e) { + throw new CloudRuntimeException("Exception while saving zone to dedicated resources", e); + } finally { + if (pstmtUpdate2 != null) { + try { + pstmtUpdate2.close(); + } catch (SQLException e) { + } + } + } + } + private void fixBaremetalForeignKeys(Connection conn) { List keys = new ArrayList(); keys.add("fk_external_dhcp_devices_nsp_id"); diff --git a/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupDao.java b/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupDao.java index 296e7b1d043..6310a2f66b4 100644 --- a/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupDao.java +++ b/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupDao.java @@ -18,6 +18,7 @@ package org.apache.cloudstack.affinity.dao; import java.util.List; +import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroupVO; import com.cloud.utils.db.GenericDao; @@ -26,5 +27,12 @@ public interface AffinityGroupDao extends GenericDao { boolean isNameInUse(Long accountId, Long domainId, String name); AffinityGroupVO findByAccountAndName(Long accountId, String name); List findByAccountAndNames(Long accountId, String... names); - int removeByAccountId(long accountId); + + int removeByAccountId(long accountId); + + AffinityGroup findDomainLevelGroupByName(Long domainId, String affinityGroupName); + + AffinityGroup findByAccountAndType(Long accountId, String string); + + AffinityGroup findDomainLevelGroupByType(Long domainId, String string); } diff --git a/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java b/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java index d189d609ff2..0be00887caa 100644 --- a/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java +++ b/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupDaoImpl.java @@ -20,18 +20,29 @@ import java.util.List; import javax.annotation.PostConstruct; import javax.ejb.Local; +import javax.inject.Inject; + +import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.affinity.AffinityGroup; +import org.apache.cloudstack.affinity.AffinityGroupDomainMapVO; import org.apache.cloudstack.affinity.AffinityGroupVO; -import org.springframework.stereotype.Component; + import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.JoinBuilder.JoinType; @Local(value = { AffinityGroupDao.class }) public class AffinityGroupDaoImpl extends GenericDaoBase implements AffinityGroupDao { private SearchBuilder AccountIdSearch; private SearchBuilder AccountIdNameSearch; private SearchBuilder AccountIdNamesSearch; - + private SearchBuilder DomainLevelNameSearch; + private SearchBuilder AccountIdTypeSearch; + @Inject + AffinityGroupDomainMapDao _groupDomainDao; + + private SearchBuilder DomainLevelTypeSearch; public AffinityGroupDaoImpl() { @@ -51,6 +62,30 @@ public class AffinityGroupDaoImpl extends GenericDaoBase AccountIdNamesSearch.and("accountId", AccountIdNamesSearch.entity().getAccountId(), SearchCriteria.Op.EQ); AccountIdNamesSearch.and("groupNames", AccountIdNamesSearch.entity().getName(), SearchCriteria.Op.IN); AccountIdNameSearch.done(); + + SearchBuilder domainMapSearch = _groupDomainDao.createSearchBuilder(); + domainMapSearch.and("domainId", domainMapSearch.entity().getDomainId(), SearchCriteria.Op.EQ); + + DomainLevelNameSearch = createSearchBuilder(); + DomainLevelNameSearch.and("name", DomainLevelNameSearch.entity().getName(), SearchCriteria.Op.EQ); + DomainLevelNameSearch.and("aclType", DomainLevelNameSearch.entity().getAclType(), SearchCriteria.Op.EQ); + DomainLevelNameSearch.join("domainMapSearch", domainMapSearch, domainMapSearch.entity().getAffinityGroupId(), + DomainLevelNameSearch.entity().getId(), JoinType.INNER); + DomainLevelNameSearch.done(); + + AccountIdTypeSearch = createSearchBuilder(); + AccountIdTypeSearch.and("accountId", AccountIdTypeSearch.entity().getAccountId(), SearchCriteria.Op.EQ); + AccountIdTypeSearch.and("type", AccountIdTypeSearch.entity().getType(), SearchCriteria.Op.EQ); + + SearchBuilder domainTypeSearch = _groupDomainDao.createSearchBuilder(); + domainTypeSearch.and("domainId", domainTypeSearch.entity().getDomainId(), SearchCriteria.Op.EQ); + DomainLevelTypeSearch = createSearchBuilder(); + DomainLevelTypeSearch.and("type", DomainLevelTypeSearch.entity().getType(), SearchCriteria.Op.EQ); + DomainLevelTypeSearch.and("aclType", DomainLevelTypeSearch.entity().getAclType(), SearchCriteria.Op.EQ); + DomainLevelTypeSearch.join("domainTypeSearch", domainTypeSearch, + domainTypeSearch.entity().getAffinityGroupId(), + DomainLevelTypeSearch.entity().getId(), JoinType.INNER); + DomainLevelTypeSearch.done(); } @Override @@ -99,4 +134,31 @@ public class AffinityGroupDaoImpl extends GenericDaoBase sc.setParameters("accountId", accountId); return expunge(sc); } + + @Override + public AffinityGroup findDomainLevelGroupByName(Long domainId, String affinityGroupName) { + SearchCriteria sc = DomainLevelNameSearch.create(); + sc.setParameters("aclType", ControlledEntity.ACLType.Domain); + sc.setParameters("name", affinityGroupName); + sc.setJoinParameters("domainMapSearch", "domainId", domainId); + return findOneBy(sc); + } + + @Override + public AffinityGroup findByAccountAndType(Long accountId, String type) { + SearchCriteria sc = AccountIdTypeSearch.create(); + sc.setParameters("accountId", accountId); + sc.setParameters("type", type); + + return findOneBy(sc); + } + + @Override + public AffinityGroup findDomainLevelGroupByType(Long domainId, String type) { + SearchCriteria sc = DomainLevelTypeSearch.create(); + sc.setParameters("aclType", ControlledEntity.ACLType.Domain); + sc.setParameters("type", type); + sc.setJoinParameters("domainTypeSearch", "domainId", domainId); + return findOneBy(sc); + } } diff --git a/plugins/affinity-group-processors/explicit-dedication/src/org/apache/cloudstack/affinity/ExplicitDedicationProcessor.java b/plugins/affinity-group-processors/explicit-dedication/src/org/apache/cloudstack/affinity/ExplicitDedicationProcessor.java index 215af7526be..5b201c61067 100644 --- a/plugins/affinity-group-processors/explicit-dedication/src/org/apache/cloudstack/affinity/ExplicitDedicationProcessor.java +++ b/plugins/affinity-group-processors/explicit-dedication/src/org/apache/cloudstack/affinity/ExplicitDedicationProcessor.java @@ -44,6 +44,9 @@ import com.cloud.domain.dao.DomainDao; import com.cloud.exception.AffinityConflictException; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; @@ -88,161 +91,173 @@ public class ExplicitDedicationProcessor extends AffinityProcessorBase implement VirtualMachine vm = vmProfile.getVirtualMachine(); List vmGroupMappings = _affinityGroupVMMapDao.findByVmIdType(vm.getId(), getType()); DataCenter dc = _dcDao.findById(vm.getDataCenterId()); - long domainId = vm.getDomainId(); - long accountId = vm.getAccountId(); + List resourceList = new ArrayList(); for (AffinityGroupVMMapVO vmGroupMapping : vmGroupMappings) { if (vmGroupMapping != null) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Processing affinity group of type 'ExplicitDedication' for VM Id: " + vm.getId()); + s_logger.debug("Processing affinity group " + vmGroupMapping.getAffinityGroupId() + + "of type 'ExplicitDedication' for VM Id: " + vm.getId()); } - List dr = _dedicatedDao.listByAccountId(accountId); - List drOfDomain = searchInDomainResources(domainId); - List drOfParentDomain = searchInParentDomainResources(domainId); - List resourceList = new ArrayList(); + long affinityGroupId = vmGroupMapping.getAffinityGroupId(); + + // List dr = _dedicatedDao.listByAccountId(accountId); + // List drOfDomain = + // searchInDomainResources(domainId); + // List drOfParentDomain = + // searchInParentDomainResources(domainId); + + List dr = _dedicatedDao.listByAffinityGroupId(affinityGroupId); resourceList.addAll(dr); - resourceList.addAll(drOfDomain); - resourceList.addAll(drOfParentDomain); - boolean canUse = false; - if (plan.getHostId() != null) { - HostVO host = _hostDao.findById(plan.getHostId()); - ClusterVO clusterofHost = _clusterDao.findById(host.getClusterId()); - HostPodVO podOfHost = _podDao.findById(host.getPodId()); - DataCenterVO zoneOfHost = _dcDao.findById(host.getDataCenterId()); - if (resourceList != null && resourceList.size() != 0) { - for(DedicatedResourceVO resource : resourceList){ - if ((resource.getHostId() != null && resource.getHostId() == plan.getHostId()) || - (resource.getClusterId() != null && resource.getClusterId() == clusterofHost.getId()) || - (resource.getPodId() != null && resource.getPodId() == podOfHost.getId()) || - (resource.getDataCenterId() != null && resource.getDataCenterId() == zoneOfHost.getId())){ - canUse = true; - } - } - } - if (!canUse) { - throw new CloudRuntimeException("Cannot use this host " + host.getName() + " for explicit dedication"); - } - } else if (plan.getClusterId() != null) { - ClusterVO cluster = _clusterDao.findById(plan.getClusterId()); - HostPodVO podOfCluster = _podDao.findById(cluster.getPodId()); - DataCenterVO zoneOfCluster = _dcDao.findById(cluster.getDataCenterId()); - List hostToUse = new ArrayList(); - // check whether this cluster or its pod is dedicated - if (resourceList != null && resourceList.size() != 0) { - for(DedicatedResourceVO resource : resourceList){ - if ((resource.getClusterId() != null && resource.getClusterId() == cluster.getId()) || - (resource.getPodId() != null && resource.getPodId() == podOfCluster.getId()) || - (resource.getDataCenterId() != null && resource.getDataCenterId() == zoneOfCluster.getId())){ - canUse = true; - } + } + } - // check for all dedicated host; if it belongs to this cluster - if (!canUse){ - if (resource.getHostId() != null) { - HostVO dHost = _hostDao.findById(resource.getHostId()); - if (dHost.getClusterId() == cluster.getId()) { - hostToUse.add(dHost); - } - } - } + boolean canUse = false; - } - } - - if (hostToUse.isEmpty() && !canUse) { - throw new CloudRuntimeException("Cannot use this cluster " + cluster.getName() + " for explicit dedication"); - } - - if (hostToUse != null && hostToUse.size() != 0) { - // add other non-dedicated hosts to avoid list - List hostList = _hostDao.findByClusterId(cluster.getId()); - for (HostVO host : hostList){ - if (!hostToUse.contains(host)) { - avoid.addHost(host.getId()); - } - } - } - - } else if (plan.getPodId() != null) { - HostPodVO pod = _podDao.findById(plan.getPodId()); - DataCenterVO zoneOfPod = _dcDao.findById(pod.getDataCenterId()); - List clustersToUse = new ArrayList(); - List hostsToUse = new ArrayList(); - // check whether this cluster or its pod is dedicated - if (resourceList != null && resourceList.size() != 0) { - for(DedicatedResourceVO resource : resourceList){ - if ((resource.getPodId() != null && resource.getPodId() == pod.getId()) || - (resource.getDataCenterId() != null && resource.getDataCenterId() == zoneOfPod.getId())){ - canUse = true; - } - - // check for all dedicated cluster/host; if it belongs to this pod - if (!canUse){ - if (resource.getClusterId() != null) { - ClusterVO dCluster = _clusterDao.findById(resource.getClusterId()); - if (dCluster.getPodId() == pod.getId()) { - clustersToUse.add(dCluster); - } - } - if (resource.getHostId() != null) { - HostVO dHost = _hostDao.findById(resource.getHostId()); - if (dHost.getPodId() == pod.getId()) { - hostsToUse.add(dHost); - } - } - } - - } - } - - if (hostsToUse.isEmpty() && clustersToUse.isEmpty() && !canUse) { - throw new CloudRuntimeException("Cannot use this pod " + pod.getName() + " for explicit dedication"); - } - - if (clustersToUse != null && clustersToUse.size() != 0) { - // add other non-dedicated clusters to avoid list - List clusterList = _clusterDao.listByPodId(pod.getId()); - for (ClusterVO cluster : clusterList){ - if (!clustersToUse.contains(cluster)) { - avoid.addCluster(cluster.getId()); - } - } - } - - if (hostsToUse != null && hostsToUse.size() != 0) { - // add other non-dedicated hosts to avoid list - List hostList = _hostDao.findByPodId(pod.getId()); - for (HostVO host : hostList){ - if (!hostsToUse.contains(host)) { - avoid.addHost(host.getId()); - } - } - } - - } else { - //check all resources under this zone - if (dr != null && dr.size() != 0) { - avoid = updateAvoidList(dr, avoid, dc); - } else if(drOfDomain != null && drOfDomain.size() != 0){ - avoid = updateAvoidList(drOfDomain, avoid, dc); - } else if(drOfParentDomain != null && drOfParentDomain.size() != 0){ - avoid = updateAvoidList(drOfParentDomain, avoid, dc); - } else { - avoid.addDataCenter(dc.getId()); - if (s_logger.isDebugEnabled()) { - s_logger.debug("No dedicated resources available for this domain or account"); - } - } - - if (s_logger.isDebugEnabled()) { - s_logger.debug("ExplicitDedicationProcessor returns Avoid List as: Deploy avoids pods: " + avoid.getPodsToAvoid() + ", clusters: " - + avoid.getClustersToAvoid() + ", hosts: " + avoid.getHostsToAvoid()); + if (plan.getHostId() != null) { + HostVO host = _hostDao.findById(plan.getHostId()); + ClusterVO clusterofHost = _clusterDao.findById(host.getClusterId()); + HostPodVO podOfHost = _podDao.findById(host.getPodId()); + DataCenterVO zoneOfHost = _dcDao.findById(host.getDataCenterId()); + if (resourceList != null && resourceList.size() != 0) { + for (DedicatedResourceVO resource : resourceList) { + if ((resource.getHostId() != null && resource.getHostId() == plan.getHostId()) + || (resource.getClusterId() != null && resource.getClusterId() == clusterofHost.getId()) + || (resource.getPodId() != null && resource.getPodId() == podOfHost.getId()) + || (resource.getDataCenterId() != null && resource.getDataCenterId() == zoneOfHost.getId())) { + canUse = true; } } } + if (!canUse) { + throw new CloudRuntimeException("Cannot use this host " + host.getName() + " for explicit dedication"); + } + } else if (plan.getClusterId() != null) { + ClusterVO cluster = _clusterDao.findById(plan.getClusterId()); + HostPodVO podOfCluster = _podDao.findById(cluster.getPodId()); + DataCenterVO zoneOfCluster = _dcDao.findById(cluster.getDataCenterId()); + List hostToUse = new ArrayList(); + // check whether this cluster or its pod is dedicated + if (resourceList != null && resourceList.size() != 0) { + for (DedicatedResourceVO resource : resourceList) { + if ((resource.getClusterId() != null && resource.getClusterId() == cluster.getId()) + || (resource.getPodId() != null && resource.getPodId() == podOfCluster.getId()) + || (resource.getDataCenterId() != null && resource.getDataCenterId() == zoneOfCluster + .getId())) { + canUse = true; + } + + // check for all dedicated host; if it belongs to this + // cluster + if (!canUse) { + if (resource.getHostId() != null) { + HostVO dHost = _hostDao.findById(resource.getHostId()); + if (dHost.getClusterId() == cluster.getId()) { + hostToUse.add(dHost); + } + } + } + + } + } + + if (hostToUse.isEmpty() && !canUse) { + throw new CloudRuntimeException("Cannot use this cluster " + cluster.getName() + + " for explicit dedication"); + } + + if (hostToUse != null && hostToUse.size() != 0) { + // add other non-dedicated hosts to avoid list + List hostList = _hostDao.findByClusterId(cluster.getId()); + for (HostVO host : hostList) { + if (!hostToUse.contains(host)) { + avoid.addHost(host.getId()); + } + } + } + + } else if (plan.getPodId() != null) { + HostPodVO pod = _podDao.findById(plan.getPodId()); + DataCenterVO zoneOfPod = _dcDao.findById(pod.getDataCenterId()); + List clustersToUse = new ArrayList(); + List hostsToUse = new ArrayList(); + // check whether this cluster or its pod is dedicated + if (resourceList != null && resourceList.size() != 0) { + for (DedicatedResourceVO resource : resourceList) { + if ((resource.getPodId() != null && resource.getPodId() == pod.getId()) + || (resource.getDataCenterId() != null && resource.getDataCenterId() == zoneOfPod.getId())) { + canUse = true; + } + + // check for all dedicated cluster/host; if it belongs to + // this pod + if (!canUse) { + if (resource.getClusterId() != null) { + ClusterVO dCluster = _clusterDao.findById(resource.getClusterId()); + if (dCluster.getPodId() == pod.getId()) { + clustersToUse.add(dCluster); + } + } + if (resource.getHostId() != null) { + HostVO dHost = _hostDao.findById(resource.getHostId()); + if (dHost.getPodId() == pod.getId()) { + hostsToUse.add(dHost); + } + } + } + + } + } + + if (hostsToUse.isEmpty() && clustersToUse.isEmpty() && !canUse) { + throw new CloudRuntimeException("Cannot use this pod " + pod.getName() + " for explicit dedication"); + } + + if (clustersToUse != null && clustersToUse.size() != 0) { + // add other non-dedicated clusters to avoid list + List clusterList = _clusterDao.listByPodId(pod.getId()); + for (ClusterVO cluster : clusterList) { + if (!clustersToUse.contains(cluster)) { + avoid.addCluster(cluster.getId()); + } + } + } + + if (hostsToUse != null && hostsToUse.size() != 0) { + // add other non-dedicated hosts to avoid list + List hostList = _hostDao.findByPodId(pod.getId()); + for (HostVO host : hostList) { + if (!hostsToUse.contains(host)) { + avoid.addHost(host.getId()); + } + } + } + + } else { + // check all resources under this zone + if (resourceList != null && resourceList.size() != 0) { + avoid = updateAvoidList(resourceList, avoid, dc); + } /* + * else if(drOfDomain != null && drOfDomain.size() != 0){ avoid = + * updateAvoidList(drOfDomain, avoid, dc); } else + * if(drOfParentDomain != null && drOfParentDomain.size() != 0){ + * avoid = updateAvoidList(drOfParentDomain, avoid, dc); } + */else { + avoid.addDataCenter(dc.getId()); + if (s_logger.isDebugEnabled()) { + s_logger.debug("No dedicated resources available for this domain or account under this group"); + } + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("ExplicitDedicationProcessor returns Avoid List as: Deploy avoids pods: " + + avoid.getPodsToAvoid() + ", clusters: " + avoid.getClustersToAvoid() + ", hosts: " + + avoid.getHostsToAvoid()); + } } + } private ExcludeList updateAvoidList(List dedicatedResources, ExcludeList avoidList, DataCenter dc) { @@ -390,4 +405,43 @@ public class ExplicitDedicationProcessor extends AffinityProcessorBase implement public boolean canBeSharedDomainWide() { return true; } + + @Override + public void handleDeleteGroup(AffinityGroup group) { + // When a group of the 'ExplicitDedication' type gets deleted, make sure + // to remove the dedicated resources in the group as well. + if (group != null) { + List dedicatedResources = _dedicatedDao.listByAffinityGroupId(group.getId()); + if (!dedicatedResources.isEmpty()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Releasing the dedicated resources under group: " + group); + } + Transaction txn = Transaction.currentTxn(); + txn.start(); + + SearchBuilder listByAffinityGroup = _dedicatedDao.createSearchBuilder(); + listByAffinityGroup.and("affinityGroupId", listByAffinityGroup.entity().getAffinityGroupId(), + SearchCriteria.Op.EQ); + listByAffinityGroup.done(); + SearchCriteria sc = listByAffinityGroup.create(); + sc.setParameters("affinityGroupId", group.getId()); + + _dedicatedDao.lockRows(sc, null, true); + _dedicatedDao.remove(sc); + + txn.commit(); + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("No dedicated resources to releease under group: " + group); + } + } + } + + return; + } + + @Override + public boolean subDomainAccess() { + return true; + } } diff --git a/plugins/dedicated-resources/src/org/apache/cloudstack/api/commands/ListDedicatedClustersCmd.java b/plugins/dedicated-resources/src/org/apache/cloudstack/api/commands/ListDedicatedClustersCmd.java index f3947876581..613f2e750e0 100644 --- a/plugins/dedicated-resources/src/org/apache/cloudstack/api/commands/ListDedicatedClustersCmd.java +++ b/plugins/dedicated-resources/src/org/apache/cloudstack/api/commands/ListDedicatedClustersCmd.java @@ -21,12 +21,14 @@ import java.util.List; import javax.inject.Inject; +import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.BaseCmd.CommandType; import org.apache.cloudstack.api.response.ClusterResponse; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.ListResponse; @@ -60,6 +62,9 @@ public class ListDedicatedClustersCmd extends BaseListCmd { description = "the name of the account associated with the cluster. Must be used with domainId.") private String accountName; + @Parameter(name = ApiConstants.AFFINITY_GROUP_ID, type = CommandType.UUID, entityType = AffinityGroupResponse.class, description = "list dedicated clusters by affinity group") + private Long affinityGroupId; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -76,6 +81,10 @@ public class ListDedicatedClustersCmd extends BaseListCmd { return accountName; } + public Long getAffinityGroupId() { + return affinityGroupId; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/plugins/dedicated-resources/src/org/apache/cloudstack/api/commands/ListDedicatedHostsCmd.java b/plugins/dedicated-resources/src/org/apache/cloudstack/api/commands/ListDedicatedHostsCmd.java index 736251b36d6..5b1a41094f0 100644 --- a/plugins/dedicated-resources/src/org/apache/cloudstack/api/commands/ListDedicatedHostsCmd.java +++ b/plugins/dedicated-resources/src/org/apache/cloudstack/api/commands/ListDedicatedHostsCmd.java @@ -21,12 +21,14 @@ import java.util.List; import javax.inject.Inject; +import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.BaseCmd.CommandType; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.HostResponse; import org.apache.cloudstack.api.response.ListResponse; @@ -60,6 +62,9 @@ public class ListDedicatedHostsCmd extends BaseListCmd { description = "the name of the account associated with the host. Must be used with domainId.") private String accountName; + @Parameter(name = ApiConstants.AFFINITY_GROUP_ID, type = CommandType.UUID, entityType = AffinityGroupResponse.class, description = "list dedicated hosts by affinity group") + private Long affinityGroupId; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -76,6 +81,10 @@ public class ListDedicatedHostsCmd extends BaseListCmd { return accountName; } + public Long getAffinityGroupId() { + return affinityGroupId; + } + ///////////////////////////////////////////////////// /////////////// API Implementation///////////////////l ///////////////////////////////////////////////////// diff --git a/plugins/dedicated-resources/src/org/apache/cloudstack/api/commands/ListDedicatedPodsCmd.java b/plugins/dedicated-resources/src/org/apache/cloudstack/api/commands/ListDedicatedPodsCmd.java index da59edae8d3..6f16d65d19e 100644 --- a/plugins/dedicated-resources/src/org/apache/cloudstack/api/commands/ListDedicatedPodsCmd.java +++ b/plugins/dedicated-resources/src/org/apache/cloudstack/api/commands/ListDedicatedPodsCmd.java @@ -21,12 +21,14 @@ import java.util.List; import javax.inject.Inject; +import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.BaseCmd.CommandType; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.PodResponse; @@ -60,6 +62,9 @@ public class ListDedicatedPodsCmd extends BaseListCmd { description = "the name of the account associated with the pod. Must be used with domainId.") private String accountName; + @Parameter(name = ApiConstants.AFFINITY_GROUP_ID, type = CommandType.UUID, entityType = AffinityGroupResponse.class, description = "list dedicated pods by affinity group") + private Long affinityGroupId; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -76,6 +81,10 @@ public class ListDedicatedPodsCmd extends BaseListCmd { return accountName; } + public Long getAffinityGroupId() { + return affinityGroupId; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/plugins/dedicated-resources/src/org/apache/cloudstack/api/commands/ListDedicatedZonesCmd.java b/plugins/dedicated-resources/src/org/apache/cloudstack/api/commands/ListDedicatedZonesCmd.java index a21f129f5be..1fc1a1961f0 100644 --- a/plugins/dedicated-resources/src/org/apache/cloudstack/api/commands/ListDedicatedZonesCmd.java +++ b/plugins/dedicated-resources/src/org/apache/cloudstack/api/commands/ListDedicatedZonesCmd.java @@ -21,12 +21,14 @@ import java.util.List; import javax.inject.Inject; +import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.BaseCmd.CommandType; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.ZoneResponse; @@ -60,6 +62,9 @@ public class ListDedicatedZonesCmd extends BaseListCmd { description = "the name of the account associated with the zone. Must be used with domainId.") private String accountName; + @Parameter(name = ApiConstants.AFFINITY_GROUP_ID, type = CommandType.UUID, entityType = AffinityGroupResponse.class, description = "list dedicated zones by affinity group") + private Long affinityGroupId; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -76,6 +81,10 @@ public class ListDedicatedZonesCmd extends BaseListCmd { return accountName; } + public Long getAffinityGroupId() { + return affinityGroupId; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/plugins/dedicated-resources/src/org/apache/cloudstack/api/response/DedicateClusterResponse.java b/plugins/dedicated-resources/src/org/apache/cloudstack/api/response/DedicateClusterResponse.java index 3c8dde3fd08..e45938c6dea 100644 --- a/plugins/dedicated-resources/src/org/apache/cloudstack/api/response/DedicateClusterResponse.java +++ b/plugins/dedicated-resources/src/org/apache/cloudstack/api/response/DedicateClusterResponse.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.api.response; +import javax.persistence.Column; + import org.apache.cloudstack.api.BaseResponse; import com.cloud.serializer.Param; @@ -37,6 +39,10 @@ public class DedicateClusterResponse extends BaseResponse { @SerializedName("accountid") @Param(description="the Account ID of the cluster") private String accountId; + @SerializedName("affinitygroupid") + @Param(description = "the Dedication Affinity Group ID of the cluster") + private String affinityGroupId; + public String getId() { return id; } @@ -76,4 +82,12 @@ public class DedicateClusterResponse extends BaseResponse { public void setAccountId(String accountId) { this.accountId = accountId; } + + public String getAffinityGroupId() { + return affinityGroupId; + } + + public void setAffinityGroupId(String affinityGroupId) { + this.affinityGroupId = affinityGroupId; + } } diff --git a/plugins/dedicated-resources/src/org/apache/cloudstack/api/response/DedicateHostResponse.java b/plugins/dedicated-resources/src/org/apache/cloudstack/api/response/DedicateHostResponse.java index cea31fe392b..83126a2490e 100644 --- a/plugins/dedicated-resources/src/org/apache/cloudstack/api/response/DedicateHostResponse.java +++ b/plugins/dedicated-resources/src/org/apache/cloudstack/api/response/DedicateHostResponse.java @@ -37,6 +37,10 @@ public class DedicateHostResponse extends BaseResponse { @SerializedName("accountid") @Param(description="the Account ID of the host") private String accountId; + @SerializedName("affinitygroupid") + @Param(description = "the Dedication Affinity Group ID of the host") + private String affinityGroupId; + public String getId() { return id; } @@ -76,4 +80,12 @@ public class DedicateHostResponse extends BaseResponse { public void setAccountId(String accountId) { this.accountId = accountId; } + + public String getAffinityGroupId() { + return affinityGroupId; + } + + public void setAffinityGroupId(String affinityGroupId) { + this.affinityGroupId = affinityGroupId; + } } diff --git a/plugins/dedicated-resources/src/org/apache/cloudstack/api/response/DedicatePodResponse.java b/plugins/dedicated-resources/src/org/apache/cloudstack/api/response/DedicatePodResponse.java index 4bcaa61c269..3705666433d 100644 --- a/plugins/dedicated-resources/src/org/apache/cloudstack/api/response/DedicatePodResponse.java +++ b/plugins/dedicated-resources/src/org/apache/cloudstack/api/response/DedicatePodResponse.java @@ -40,6 +40,10 @@ public class DedicatePodResponse extends BaseResponse { @SerializedName("accountid") @Param(description="the Account Id to which the Pod is dedicated") private String accountId; + @SerializedName("affinitygroupid") + @Param(description = "the Dedication Affinity Group ID of the pod") + private String affinityGroupId; + public String getId() { return id; } @@ -79,4 +83,12 @@ public class DedicatePodResponse extends BaseResponse { public void setAccountId(String accountId) { this.accountId = accountId; } + + public String getAffinityGroupId() { + return affinityGroupId; + } + + public void setAffinityGroupId(String affinityGroupId) { + this.affinityGroupId = affinityGroupId; + } } diff --git a/plugins/dedicated-resources/src/org/apache/cloudstack/api/response/DedicateZoneResponse.java b/plugins/dedicated-resources/src/org/apache/cloudstack/api/response/DedicateZoneResponse.java index 57497cd3484..ee067ed1a1a 100644 --- a/plugins/dedicated-resources/src/org/apache/cloudstack/api/response/DedicateZoneResponse.java +++ b/plugins/dedicated-resources/src/org/apache/cloudstack/api/response/DedicateZoneResponse.java @@ -40,6 +40,10 @@ public class DedicateZoneResponse extends BaseResponse { @SerializedName("accountid") @Param(description="the Account Id to which the Zone is dedicated") private String accountId; + @SerializedName("affinitygroupid") + @Param(description = "the Dedication Affinity Group ID of the zone") + private String affinityGroupId; + public String getId() { return id; } @@ -80,4 +84,11 @@ public class DedicateZoneResponse extends BaseResponse { this.accountId = accountId; } + public String getAffinityGroupId() { + return affinityGroupId; + } + + public void setAffinityGroupId(String affinityGroupId) { + this.affinityGroupId = affinityGroupId; + } } diff --git a/plugins/dedicated-resources/src/org/apache/cloudstack/dedicated/DedicatedResourceManagerImpl.java b/plugins/dedicated-resources/src/org/apache/cloudstack/dedicated/DedicatedResourceManagerImpl.java index 3314463c06d..68adb2bfa6a 100755 --- a/plugins/dedicated-resources/src/org/apache/cloudstack/dedicated/DedicatedResourceManagerImpl.java +++ b/plugins/dedicated-resources/src/org/apache/cloudstack/dedicated/DedicatedResourceManagerImpl.java @@ -26,6 +26,10 @@ import javax.naming.ConfigurationException; import com.cloud.utils.component.AdapterBase; +import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.affinity.AffinityGroup; +import org.apache.cloudstack.affinity.AffinityGroupService; +import org.apache.cloudstack.affinity.dao.AffinityGroupDao; import org.apache.cloudstack.api.commands.DedicateClusterCmd; import org.apache.cloudstack.api.commands.DedicateHostCmd; import org.apache.cloudstack.api.commands.DedicatePodCmd; @@ -94,6 +98,10 @@ public class DedicatedResourceManagerImpl implements DedicatedService { @Inject AccountManager _accountMgr; @Inject UserVmDao _userVmDao; @Inject ConfigurationDao _configDao; + @Inject AffinityGroupDao _affinityGroupDao; + + @Inject + AffinityGroupService _affinityGroupService; private int capacityReleaseInterval; @@ -214,7 +222,15 @@ public class DedicatedResourceManagerImpl implements DedicatedService { Transaction txn = Transaction.currentTxn(); txn.start(); - DedicatedResourceVO dedicatedResource = new DedicatedResourceVO(zoneId, null, null, null, null, null); + // find or create the affinity group by name under this account/domain + AffinityGroup group = findOrCreateDedicatedAffinityGroup(domainId, accountId); + if (group == null) { + s_logger.error("Unable to dedicate zone due to, failed to create dedication affinity group"); + throw new CloudRuntimeException("Failed to dedicate zone. Please contact Cloud Support."); + } + + DedicatedResourceVO dedicatedResource = new DedicatedResourceVO(zoneId, null, null, null, null, null, + group.getId()); try { dedicatedResource.setDomainId(domainId); if (accountId != null) { @@ -331,7 +347,14 @@ public class DedicatedResourceManagerImpl implements DedicatedService { Transaction txn = Transaction.currentTxn(); txn.start(); - DedicatedResourceVO dedicatedResource = new DedicatedResourceVO(null, podId, null, null, null, null); + // find or create the affinity group by name under this account/domain + AffinityGroup group = findOrCreateDedicatedAffinityGroup(domainId, accountId); + if (group == null) { + s_logger.error("Unable to dedicate zone due to, failed to create dedication affinity group"); + throw new CloudRuntimeException("Failed to dedicate zone. Please contact Cloud Support."); + } + DedicatedResourceVO dedicatedResource = new DedicatedResourceVO(null, podId, null, null, null, null, + group.getId()); try { dedicatedResource.setDomainId(domainId); if (accountId != null) { @@ -434,7 +457,14 @@ public class DedicatedResourceManagerImpl implements DedicatedService { Transaction txn = Transaction.currentTxn(); txn.start(); - DedicatedResourceVO dedicatedResource = new DedicatedResourceVO(null, null, clusterId, null, null, null); + // find or create the affinity group by name under this account/domain + AffinityGroup group = findOrCreateDedicatedAffinityGroup(domainId, accountId); + if (group == null) { + s_logger.error("Unable to dedicate zone due to, failed to create dedication affinity group"); + throw new CloudRuntimeException("Failed to dedicate zone. Please contact Cloud Support."); + } + DedicatedResourceVO dedicatedResource = new DedicatedResourceVO(null, null, clusterId, null, null, null, + group.getId()); try { dedicatedResource.setDomainId(domainId); if (accountId != null) { @@ -522,7 +552,14 @@ public class DedicatedResourceManagerImpl implements DedicatedService { Transaction txn = Transaction.currentTxn(); txn.start(); - DedicatedResourceVO dedicatedResource = new DedicatedResourceVO(null, null, null, hostId, null, null); + // find or create the affinity group by name under this account/domain + AffinityGroup group = findOrCreateDedicatedAffinityGroup(domainId, accountId); + if (group == null) { + s_logger.error("Unable to dedicate zone due to, failed to create dedication affinity group"); + throw new CloudRuntimeException("Failed to dedicate zone. Please contact Cloud Support."); + } + DedicatedResourceVO dedicatedResource = new DedicatedResourceVO(null, null, null, hostId, null, null, + group.getId()); try { dedicatedResource.setDomainId(domainId); if (accountId != null) { @@ -540,6 +577,45 @@ public class DedicatedResourceManagerImpl implements DedicatedService { return result; } + private AffinityGroup findOrCreateDedicatedAffinityGroup(Long domainId, Long accountId) { + if(domainId == null){ + return null; + } + + AffinityGroup group = null; + String accountName = null; + String affinityGroupName = null; + + if (accountId != null) { + AccountVO account = _accountDao.findById(accountId); + accountName = account.getAccountName(); + + group = _affinityGroupDao.findByAccountAndType(accountId, "ExplicitDedication"); + if (group != null) { + return group; + } + // default to a groupname with account/domain information + affinityGroupName = "DedicatedGrp-" + accountName; + + } else { + // domain level group + group = _affinityGroupDao.findDomainLevelGroupByType(domainId, "ExplicitDedication"); + if (group != null) { + return group; + } + // default to a groupname with account/domain information + String domainName = _domainDao.findById(domainId).getName(); + affinityGroupName = "DedicatedGrp-domain-" + domainName; + } + + + group = _affinityGroupService.createAffinityGroup(accountName, domainId, affinityGroupName, + "ExplicitDedication", "dedicated resources group"); + + return group; + + } + private List getVmsOnHost(long hostId) { List vms = _userVmDao.listUpByHostId(hostId); List vmsByLastHostId = _userVmDao.listByLastHostId(hostId); @@ -622,10 +698,12 @@ public class DedicatedResourceManagerImpl implements DedicatedService { DataCenterVO dc = _zoneDao.findById(resource.getDataCenterId()); DomainVO domain = _domainDao.findById(resource.getDomainId()); AccountVO account = _accountDao.findById(resource.getAccountId()); + AffinityGroup group = _affinityGroupDao.findById(resource.getAffinityGroupId()); dedicateZoneResponse.setId(resource.getUuid()); dedicateZoneResponse.setZoneId(dc.getUuid()); dedicateZoneResponse.setZoneName(dc.getName()); dedicateZoneResponse.setDomainId(domain.getUuid()); + dedicateZoneResponse.setAffinityGroupId(group.getUuid()); if (account != null) { dedicateZoneResponse.setAccountId(account.getUuid()); } @@ -639,10 +717,12 @@ public class DedicatedResourceManagerImpl implements DedicatedService { HostPodVO pod = _podDao.findById(resource.getPodId()); DomainVO domain = _domainDao.findById(resource.getDomainId()); AccountVO account = _accountDao.findById(resource.getAccountId()); + AffinityGroup group = _affinityGroupDao.findById(resource.getAffinityGroupId()); dedicatePodResponse.setId(resource.getUuid()); dedicatePodResponse.setPodId(pod.getUuid()); dedicatePodResponse.setPodName(pod.getName()); dedicatePodResponse.setDomainId(domain.getUuid()); + dedicatePodResponse.setAffinityGroupId(group.getUuid()); if (account != null) { dedicatePodResponse.setAccountId(account.getUuid()); } @@ -656,10 +736,12 @@ public class DedicatedResourceManagerImpl implements DedicatedService { ClusterVO cluster = _clusterDao.findById(resource.getClusterId()); DomainVO domain = _domainDao.findById(resource.getDomainId()); AccountVO account = _accountDao.findById(resource.getAccountId()); + AffinityGroup group = _affinityGroupDao.findById(resource.getAffinityGroupId()); dedicateClusterResponse.setId(resource.getUuid()); dedicateClusterResponse.setClusterId(cluster.getUuid()); dedicateClusterResponse.setClusterName(cluster.getName()); dedicateClusterResponse.setDomainId(domain.getUuid()); + dedicateClusterResponse.setAffinityGroupId(group.getUuid()); if (account != null) { dedicateClusterResponse.setAccountId(account.getUuid()); } @@ -673,10 +755,12 @@ public class DedicatedResourceManagerImpl implements DedicatedService { HostVO host = _hostDao.findById(resource.getHostId()); DomainVO domain = _domainDao.findById(resource.getDomainId()); AccountVO account = _accountDao.findById(resource.getAccountId()); + AffinityGroup group = _affinityGroupDao.findById(resource.getAffinityGroupId()); dedicateHostResponse.setId(resource.getUuid()); dedicateHostResponse.setHostId(host.getUuid()); dedicateHostResponse.setHostName(host.getName()); dedicateHostResponse.setDomainId(domain.getUuid()); + dedicateHostResponse.setAffinityGroupId(group.getUuid()); if (account != null) { dedicateHostResponse.setAccountId(account.getUuid()); } @@ -708,6 +792,8 @@ public class DedicatedResourceManagerImpl implements DedicatedService { Long domainId = cmd.getDomainId(); String accountName = cmd.getAccountName(); Long accountId = null; + Long affinityGroupId = cmd.getAffinityGroupId(); + if (accountName != null) { if (domainId != null) { Account account = _accountDao.findActiveAccount(accountName, domainId); @@ -718,7 +804,8 @@ public class DedicatedResourceManagerImpl implements DedicatedService { throw new InvalidParameterValueException("Please specify the domain id of the account: " + accountName); } } - Pair, Integer> result = _dedicatedDao.searchDedicatedZones(zoneId, domainId, accountId); + Pair, Integer> result = _dedicatedDao.searchDedicatedZones(zoneId, domainId, + accountId, affinityGroupId); return new Pair, Integer>(result.first(), result.second()); } @@ -728,6 +815,8 @@ public class DedicatedResourceManagerImpl implements DedicatedService { Long domainId = cmd.getDomainId(); String accountName = cmd.getAccountName(); Long accountId = null; + Long affinityGroupId = cmd.getAffinityGroupId(); + if (accountName != null) { if (domainId != null) { Account account = _accountDao.findActiveAccount(accountName, domainId); @@ -738,7 +827,8 @@ public class DedicatedResourceManagerImpl implements DedicatedService { throw new InvalidParameterValueException("Please specify the domain id of the account: " + accountName); } } - Pair, Integer> result = _dedicatedDao.searchDedicatedPods(podId, domainId, accountId); + Pair, Integer> result = _dedicatedDao.searchDedicatedPods(podId, domainId, accountId, + affinityGroupId); return new Pair, Integer>(result.first(), result.second()); } @@ -748,6 +838,8 @@ public class DedicatedResourceManagerImpl implements DedicatedService { Long domainId = cmd.getDomainId(); String accountName = cmd.getAccountName(); Long accountId = null; + Long affinityGroupId = cmd.getAffinityGroupId(); + if (accountName != null) { if (domainId != null) { Account account = _accountDao.findActiveAccount(accountName, domainId); @@ -758,7 +850,8 @@ public class DedicatedResourceManagerImpl implements DedicatedService { throw new InvalidParameterValueException("Please specify the domain id of the account: " + accountName); } } - Pair, Integer> result = _dedicatedDao.searchDedicatedClusters(clusterId, domainId, accountId); + Pair, Integer> result = _dedicatedDao.searchDedicatedClusters(clusterId, domainId, + accountId, affinityGroupId); return new Pair, Integer>(result.first(), result.second()); } @@ -767,6 +860,8 @@ public class DedicatedResourceManagerImpl implements DedicatedService { Long hostId = cmd.getHostId(); Long domainId = cmd.getDomainId(); String accountName = cmd.getAccountName(); + Long affinityGroupId = cmd.getAffinityGroupId(); + Long accountId = null; if (accountName != null) { if (domainId != null) { @@ -779,7 +874,7 @@ public class DedicatedResourceManagerImpl implements DedicatedService { } } - Pair, Integer> result = _dedicatedDao.searchDedicatedHosts(hostId, domainId, accountId); + Pair, Integer> result = _dedicatedDao.searchDedicatedHosts(hostId, domainId, accountId, affinityGroupId); return new Pair, Integer>(result.first(), result.second()); } @@ -811,6 +906,16 @@ public class DedicatedResourceManagerImpl implements DedicatedService { throw new CloudRuntimeException("Failed to delete Resource " + resourceId); } txn.commit(); + + // find the group associated and check if there are any more + // resources under that group + List resourcesInGroup = _dedicatedDao.listByAffinityGroupId(resource + .getAffinityGroupId()); + if (resourcesInGroup.isEmpty()) { + // delete the group + _affinityGroupService.deleteAffinityGroup(resource.getAffinityGroupId(), null, null, null); + } + } return true; } diff --git a/plugins/dedicated-resources/test/org/apache/cloudstack/dedicated/manager/DedicatedApiUnitTest.java b/plugins/dedicated-resources/test/org/apache/cloudstack/dedicated/manager/DedicatedApiUnitTest.java index 34fdf1c8ead..f2803b11f59 100644 --- a/plugins/dedicated-resources/test/org/apache/cloudstack/dedicated/manager/DedicatedApiUnitTest.java +++ b/plugins/dedicated-resources/test/org/apache/cloudstack/dedicated/manager/DedicatedApiUnitTest.java @@ -28,6 +28,10 @@ import javax.inject.Inject; import junit.framework.Assert; +import org.apache.cloudstack.affinity.AffinityGroupService; +import org.apache.cloudstack.affinity.dao.AffinityGroupDao; +import org.apache.cloudstack.dedicated.DedicatedResourceManagerImpl; +import org.apache.cloudstack.test.utils.SpringUtils; import org.apache.log4j.Logger; import org.junit.After; import org.junit.Before; @@ -212,28 +216,28 @@ public class DedicatedApiUnitTest { @Test(expected = CloudRuntimeException.class) public void dedicateZoneExistTest() { - DedicatedResourceVO dr = new DedicatedResourceVO(10L, null, null, null, domainId, accountId); + DedicatedResourceVO dr = new DedicatedResourceVO(10L, null, null, null, domainId, accountId, 12L); when(_dedicatedDao.findByZoneId(10L)).thenReturn(dr); _dedicatedService.dedicateZone(10L, domainId, accountName); } @Test(expected = CloudRuntimeException.class) public void dedicatePodExistTest() { - DedicatedResourceVO dr = new DedicatedResourceVO(null, 10L, null, null, domainId, accountId); + DedicatedResourceVO dr = new DedicatedResourceVO(null, 10L, null, null, domainId, accountId, 12L); when(_dedicatedDao.findByPodId(10L)).thenReturn(dr); _dedicatedService.dedicatePod(10L, domainId, accountName); } @Test(expected = CloudRuntimeException.class) public void dedicateClusterExistTest() { - DedicatedResourceVO dr = new DedicatedResourceVO(null, null, 10L, null, domainId, accountId); + DedicatedResourceVO dr = new DedicatedResourceVO(null, null, 10L, null, domainId, accountId, 12L); when(_dedicatedDao.findByClusterId(10L)).thenReturn(dr); _dedicatedService.dedicateCluster(10L, domainId, accountName); } @Test(expected = CloudRuntimeException.class) public void dedicateHostExistTest() { - DedicatedResourceVO dr = new DedicatedResourceVO(null, null, null, 10L, domainId, accountId); + DedicatedResourceVO dr = new DedicatedResourceVO(null, null, null, 10L, domainId, accountId, 12L); when(_dedicatedDao.findByHostId(10L)).thenReturn(dr); _dedicatedService.dedicateHost(10L, domainId, accountName); } @@ -310,6 +314,16 @@ public class DedicatedApiUnitTest { return Mockito.mock(ConfigurationDao.class); } + @Bean + public AffinityGroupService affinityGroupService() { + return Mockito.mock(AffinityGroupService.class); + } + + @Bean + public AffinityGroupDao affinityGroupDao() { + return Mockito.mock(AffinityGroupDao.class); + } + public static class Library implements TypeFilter { @Override public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { diff --git a/server/src/com/cloud/acl/AffinityGroupAccessChecker.java b/server/src/com/cloud/acl/AffinityGroupAccessChecker.java index fcebf2f5b26..bc1e631e445 100644 --- a/server/src/com/cloud/acl/AffinityGroupAccessChecker.java +++ b/server/src/com/cloud/acl/AffinityGroupAccessChecker.java @@ -69,6 +69,8 @@ public class AffinityGroupAccessChecker extends DomainChecker { if (caller.getId() != group.getAccountId()) { throw new PermissionDeniedException(caller + " does not have permission to operate with resource " + entity); + }else{ + return true; } } diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index 2fdc9f2e9fd..b017ef18650 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -41,6 +41,10 @@ import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import org.apache.cloudstack.acl.SecurityChecker; +import org.apache.cloudstack.affinity.AffinityGroup; +import org.apache.cloudstack.affinity.AffinityGroupService; +import org.apache.cloudstack.affinity.dao.AffinityGroupDao; +import org.apache.cloudstack.api.ApiConstants.LDAPParams; import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd; import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd; import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd; @@ -301,6 +305,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati DedicatedResourceDao _dedicatedDao; @Inject IpAddressManager _ipAddrMgr; + @Inject + AffinityGroupDao _affinityGroupDao; + @Inject + AffinityGroupService _affinityGroupService; // FIXME - why don't we have interface for DataCenterLinkLocalIpAddressDao? @Inject @@ -1799,8 +1807,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati zone = _zoneDao.persist(zone); if (domainId != null) { // zone is explicitly dedicated to this domain + // create affinity group associated. + AffinityGroup group = createDedicatedAffinityGroup(null, domainId, null); DedicatedResourceVO dedicatedResource = new DedicatedResourceVO(zone.getId(), null, null, null, - domainId, null); + domainId, null, group.getId()); _dedicatedDao.persist(dedicatedResource); } @@ -1817,6 +1827,38 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } } + private AffinityGroup createDedicatedAffinityGroup(String affinityGroupName, Long domainId, Long accountId) { + if (affinityGroupName == null) { + // default to a groupname with account/domain information + affinityGroupName = "ZoneDedicatedGrp-domain-" + domainId + (accountId != null ? "-acct-" + accountId : ""); + } + + AffinityGroup group = null; + String accountName = null; + + if (accountId != null) { + AccountVO account = _accountDao.findById(accountId); + accountName = account.getAccountName(); + + group = _affinityGroupDao.findByAccountAndName(accountId, affinityGroupName); + if (group != null) { + return group; + } + } else { + // domain level group + group = _affinityGroupDao.findDomainLevelGroupByName(domainId, affinityGroupName); + if (group != null) { + return group; + } + } + + group = _affinityGroupService.createAffinityGroup(accountName, domainId, affinityGroupName, + "ExplicitDedication", "dedicated resources group"); + + return group; + + } + @Override public void createDefaultSystemNetworks(long zoneId) throws ConcurrentOperationException { DataCenterVO zone = _zoneDao.findById(zoneId); diff --git a/server/src/com/cloud/dc/DedicatedResourceVO.java b/server/src/com/cloud/dc/DedicatedResourceVO.java index a4c88f57e02..f1ec6a159ac 100644 --- a/server/src/com/cloud/dc/DedicatedResourceVO.java +++ b/server/src/com/cloud/dc/DedicatedResourceVO.java @@ -56,11 +56,15 @@ public class DedicatedResourceVO implements DedicatedResources{ @Column(name = "account_id") private Long accountId; + @Column(name = "affinity_group_id") + private long affinityGroupId; + public DedicatedResourceVO() { this.uuid = UUID.randomUUID().toString(); } - public DedicatedResourceVO(Long dataCenterId, Long podId, Long clusterId, Long hostId, Long domainId, Long accountId) { + public DedicatedResourceVO(Long dataCenterId, Long podId, Long clusterId, Long hostId, Long domainId, + Long accountId, long affinityGroupId) { this.dataCenterId = dataCenterId; this.podId = podId; this.clusterId = clusterId; @@ -68,6 +72,7 @@ public class DedicatedResourceVO implements DedicatedResources{ this.domainId = domainId; this.accountId = accountId; this.uuid = UUID.randomUUID().toString(); + this.affinityGroupId = affinityGroupId; } public long getId() { @@ -133,4 +138,8 @@ public class DedicatedResourceVO implements DedicatedResources{ public void setUuid(String uuid) { this.uuid = uuid; } + + public long getAffinityGroupId() { + return affinityGroupId; + } } diff --git a/server/src/com/cloud/dc/dao/DedicatedResourceDao.java b/server/src/com/cloud/dc/dao/DedicatedResourceDao.java index 2eef83a120c..865e083320a 100644 --- a/server/src/com/cloud/dc/dao/DedicatedResourceDao.java +++ b/server/src/com/cloud/dc/dao/DedicatedResourceDao.java @@ -33,13 +33,13 @@ public interface DedicatedResourceDao extends GenericDao, Integer> searchDedicatedHosts(Long hostId, Long domainId, Long accountId); + Pair, Integer> searchDedicatedHosts(Long hostId, Long domainId, Long accountId, Long affinityGroupId); - Pair, Integer> searchDedicatedClusters(Long clusterId, Long domainId, Long accountId); + Pair, Integer> searchDedicatedClusters(Long clusterId, Long domainId, Long accountId, Long affinityGroupId); - Pair, Integer> searchDedicatedPods(Long podId, Long domainId, Long accountId); + Pair, Integer> searchDedicatedPods(Long podId, Long domainId, Long accountId, Long affinityGroupId); - Pair, Integer> searchDedicatedZones(Long dataCenterId, Long domainId, Long accountId); + Pair, Integer> searchDedicatedZones(Long dataCenterId, Long domainId, Long accountId, Long affinityGroupId); List listByAccountId(Long accountId); @@ -52,4 +52,7 @@ public interface DedicatedResourceDao extends GenericDao listAllClusters(); List listAllHosts(); + + List listByAffinityGroupId(Long affinityGroupId); + } \ No newline at end of file diff --git a/server/src/com/cloud/dc/dao/DedicatedResourceDaoImpl.java b/server/src/com/cloud/dc/dao/DedicatedResourceDaoImpl.java index 266e65fb880..bc58021a4d4 100644 --- a/server/src/com/cloud/dc/dao/DedicatedResourceDaoImpl.java +++ b/server/src/com/cloud/dc/dao/DedicatedResourceDaoImpl.java @@ -59,7 +59,7 @@ public class DedicatedResourceDaoImpl extends GenericDaoBase ListByAccountId; protected SearchBuilder ListByDomainId; - + protected SearchBuilder ListByAffinityGroupId; protected SearchBuilder ZoneByDomainIdsSearch; protected GenericSearchBuilder ListPodsSearch; @@ -134,6 +134,7 @@ public class DedicatedResourceDaoImpl extends GenericDaoBase, Integer> searchDedicatedZones(Long dataCenterId, Long domainId, Long accountId){ + public Pair, Integer> searchDedicatedZones(Long dataCenterId, Long domainId, + Long accountId, Long affinityGroupId) { SearchCriteria sc = ListAllZonesSearch.create(); if (dataCenterId != null) { sc.setParameters("zoneId", dataCenterId); } + if (affinityGroupId != null) { + sc.setParameters("affinityGroupId", affinityGroupId); + } if(domainId != null) { sc.setParameters("domainId", domainId); if(accountId != null) { @@ -241,11 +254,15 @@ public class DedicatedResourceDaoImpl extends GenericDaoBase, Integer> searchDedicatedPods(Long podId, Long domainId, Long accountId){ + public Pair, Integer> searchDedicatedPods(Long podId, Long domainId, Long accountId, + Long affinityGroupId) { SearchCriteria sc = ListAllPodsSearch.create(); if (podId != null) { sc.setParameters("podId", podId); } + if (affinityGroupId != null) { + sc.setParameters("affinityGroupId", affinityGroupId); + } if(domainId != null) { sc.setParameters("domainId", domainId); if(accountId != null) { @@ -258,11 +275,16 @@ public class DedicatedResourceDaoImpl extends GenericDaoBase, Integer> searchDedicatedClusters(Long clusterId, Long domainId, Long accountId){ + public Pair, Integer> searchDedicatedClusters(Long clusterId, Long domainId, + Long accountId, Long affinityGroupId) { SearchCriteria sc = ListAllClustersSearch.create(); if (clusterId != null) { sc.setParameters("clusterId", clusterId); } + if (affinityGroupId != null) { + sc.setParameters("affinityGroupId", affinityGroupId); + } + if(domainId != null) { sc.setParameters("domainId", domainId); if(accountId != null) { @@ -275,11 +297,14 @@ public class DedicatedResourceDaoImpl extends GenericDaoBase, Integer> searchDedicatedHosts(Long hostId, Long domainId, Long accountId){ + public Pair, Integer> searchDedicatedHosts(Long hostId, Long domainId, Long accountId, Long affinityGroupId){ SearchCriteria sc = ListAllHostsSearch.create(); if (hostId != null) { sc.setParameters("hostId", hostId); } + if (affinityGroupId != null) { + sc.setParameters("affinityGroupId", affinityGroupId); + } if(domainId != null) { sc.setParameters("domainId", domainId); if(accountId != null) { @@ -341,4 +366,11 @@ public class DedicatedResourceDaoImpl extends GenericDaoBase sc = ListHostsSearch.create(); return customSearch(sc, null); } + + @Override + public List listByAffinityGroupId(Long affinityGroupId) { + SearchCriteria sc = ListByAffinityGroupId.create(); + sc.setParameters("affinityGroupId", affinityGroupId); + return listBy(sc); + } } diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java index 252cf8ae630..cdd46ce7eb2 100644 --- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -30,6 +30,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import org.apache.cloudstack.affinity.AffinityGroupProcessor; +import org.apache.cloudstack.affinity.AffinityGroupService; import org.apache.cloudstack.affinity.AffinityGroupVMMapVO; import org.apache.cloudstack.affinity.AffinityGroupVO; import org.apache.cloudstack.affinity.dao.AffinityGroupDao; @@ -66,6 +67,7 @@ import com.cloud.deploy.dao.PlannerHostReservationDao; import com.cloud.exception.AffinityConflictException; import com.cloud.exception.ConnectionException; import com.cloud.exception.InsufficientServerCapacityException; +import com.cloud.exception.PermissionDeniedException; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.Status; @@ -133,6 +135,8 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy @Inject protected AffinityGroupVMMapDao _affinityGroupVMMapDao; @Inject + AffinityGroupService _affinityGroupService; + @Inject DataCenterDao _dcDao; @Inject PlannerHostReservationDao _plannerHostReserveDao; @@ -215,7 +219,9 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy } } - checkForNonDedicatedResources(vmProfile, dc, avoids); + if (vm.getType() == VirtualMachine.Type.User) { + checkForNonDedicatedResources(vmProfile, dc, avoids); + } if (s_logger.isDebugEnabled()) { s_logger.debug("Deploy avoids pods: " + avoids.getPodsToAvoid() + ", clusters: " + avoids.getClustersToAvoid() + ", hosts: " + avoids.getHostsToAvoid()); @@ -444,20 +450,48 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy private void checkForNonDedicatedResources(VirtualMachineProfile vmProfile, DataCenter dc, ExcludeList avoids) { boolean isExplicit = false; - VirtualMachine vm = vmProfile.getVirtualMachine(); - // check affinity group of type Explicit dedication exists + VirtualMachine vm = vmProfile.getVirtualMachine(); + + // check if zone is dedicated. if yes check if vm owner has acess to it. + DedicatedResourceVO dedicatedZone = _dedicatedDao.findByZoneId(dc.getId()); + if (dedicatedZone != null) { + long accountDomainId = vmProfile.getOwner().getDomainId(); + long accountId = vmProfile.getOwner().getAccountId(); + + // If a zone is dedicated to an account then all hosts in this zone + // will be explicitly dedicated to + // that account. So there won't be any shared hosts in the zone, the + // only way to deploy vms from that + // account will be to use explicit dedication affinity group. + if (dedicatedZone.getAccountId() != null) { + if (dedicatedZone.getAccountId().equals(accountId)) { + return; + } else { + throw new CloudRuntimeException("Failed to deploy VM, Zone " + dc.getName() + + " not available for the user account " + vmProfile.getOwner()); + } + } + + // if zone is dedicated to a domain. Check owner's access to the + // domain level dedication group + if (!_affinityGroupService.isAffinityGroupAvailableInDomain(dedicatedZone.getAffinityGroupId(), + accountDomainId)) { + throw new CloudRuntimeException("Failed to deploy VM, Zone " + dc.getName() + + " not available for the user domain " + vmProfile.getOwner()); + } + + } + + // check affinity group of type Explicit dedication exists. If No put + // dedicated pod/cluster/host in avoid list List vmGroupMappings = _affinityGroupVMMapDao.findByVmIdType(vm.getId(), "ExplicitDedication"); if (vmGroupMappings != null && !vmGroupMappings.isEmpty()){ isExplicit = true; } - if (!isExplicit && vm.getType() == VirtualMachine.Type.User) { + if (!isExplicit) { //add explicitly dedicated resources in avoidList - DedicatedResourceVO dedicatedZone = _dedicatedDao.findByZoneId(dc.getId()); - if (dedicatedZone != null && dedicatedZone.getDomainId() != null) { - throw new CloudRuntimeException("Failed to deploy VM. Zone " + dc.getName() + " is dedicated . Please use Explicit Dedication Affinity Group"); - } List allPodsInDc = _podDao.listAllPods(dc.getId()); List allDedicatedPods = _dedicatedDao.listAllPods(); diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 1ce3f208029..53211e1a445 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2503,20 +2503,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir + zone.getId()); } - boolean isExplicit = false; - // check affinity group type Explicit dedication - if (affinityGroupIdList != null) { - for (Long affinityGroupId : affinityGroupIdList) { - AffinityGroupVO ag = _affinityGroupDao.findById(affinityGroupId); - String agType = ag.getType(); - if (agType.equals("ExplicitDedication")) { - isExplicit = true; - } - } - } // check if zone is dedicated DedicatedResourceVO dedicatedZone = _dedicatedDao.findByZoneId(zone.getId()); - if (isExplicit && dedicatedZone != null) { + if (dedicatedZone != null) { DomainVO domain = _domainDao.findById(dedicatedZone.getDomainId()); if (domain == null) { throw new CloudRuntimeException("Unable to find the domain " diff --git a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java index 06c04cbcba9..c6f1b92848d 100644 --- a/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java +++ b/server/src/org/apache/cloudstack/affinity/AffinityGroupServiceImpl.java @@ -140,6 +140,7 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro ControlledEntity.ACLType aclType = null; Account owner = null; + boolean domainLevel = false; if (account != null && domainId != null) { @@ -166,6 +167,7 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro // domain level group, owner is SYSTEM. owner = _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM); aclType = ControlledEntity.ACLType.Domain; + domainLevel = true; } else { owner = caller; @@ -176,6 +178,10 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro throw new InvalidParameterValueException("Unable to create affinity group, a group with name " + affinityGroupName + " already exisits."); } + if (domainLevel && _affinityGroupDao.findDomainLevelGroupByName(domainId, affinityGroupName) != null) { + throw new InvalidParameterValueException("Unable to create affinity group, a group with name " + + affinityGroupName + " already exisits under the domain."); + } Transaction txn = Transaction.currentTxn(); txn.start(); @@ -185,7 +191,9 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro _affinityGroupDao.persist(group); if (domainId != null && aclType == ACLType.Domain) { - AffinityGroupDomainMapVO domainMap = new AffinityGroupDomainMapVO(group.getId(), domainId, false); + boolean subDomainAccess = false; + subDomainAccess = processor.subDomainAccess(); + AffinityGroupDomainMapVO domainMap = new AffinityGroupDomainMapVO(group.getId(), domainId, subDomainAccess); _affinityGroupDomainMapDao.persist(domainMap); } @@ -251,6 +259,12 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro _affinityGroupVMMapDao.remove(sc); } + // call processor to handle the group delete + AffinityGroupProcessor processor = getAffinityGroupProcessorForType(group.getType()); + if (processor != null) { + processor.handleDeleteGroup(group); + } + _affinityGroupDao.expunge(affinityGroupId); txn.commit(); @@ -324,8 +338,9 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro if (componentMap.size() > 0) { for (Entry entry : componentMap.entrySet()) { AffinityGroupProcessor processor = entry.getValue(); - if (processor.isAdminControlledGroup() && !_accountMgr.isRootAdmin(caller.getType())) { - continue; + if (processor.isAdminControlledGroup()) { + continue; // we dont list the type if this group can be + // created only as an admin/system operation. } types.add(processor.getType()); } @@ -469,6 +484,15 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro return false; } + private AffinityGroupProcessor getAffinityGroupProcessorForType(String affinityGroupType) { + for (AffinityGroupProcessor processor : _affinityProcessors) { + if (affinityGroupType != null && affinityGroupType.equals(processor.getType())) { + return processor; + } + } + return null; + } + @Override public boolean isAffinityGroupAvailableInDomain(long affinityGroupId, long domainId) { Long groupDomainId = null; diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index ba9932fed98..5887caaeb57 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -447,6 +447,7 @@ CREATE TABLE `cloud`.`dedicated_resources` ( `host_id` bigint unsigned COMMENT 'host id', `domain_id` bigint unsigned COMMENT 'domain id of the domain to which resource is dedicated', `account_id` bigint unsigned COMMENT 'account id of the account to which resource is dedicated', + `affinity_group_id` bigint unsigned NOT NULL COMMENT 'affinity group id associated', PRIMARY KEY (`id`), CONSTRAINT `fk_dedicated_resources__data_center_id` FOREIGN KEY (`data_center_id`) REFERENCES `cloud`.`data_center`(`id`) ON DELETE CASCADE, CONSTRAINT `fk_dedicated_resources__pod_id` FOREIGN KEY (`pod_id`) REFERENCES `cloud`.`host_pod_ref`(`id`), @@ -454,8 +455,10 @@ CREATE TABLE `cloud`.`dedicated_resources` ( CONSTRAINT `fk_dedicated_resources__host_id` FOREIGN KEY (`host_id`) REFERENCES `cloud`.`host`(`id`), CONSTRAINT `fk_dedicated_resources__domain_id` FOREIGN KEY (`domain_id`) REFERENCES `domain`(`id`), CONSTRAINT `fk_dedicated_resources__account_id` FOREIGN KEY (`account_id`) REFERENCES `account`(`id`), + CONSTRAINT `fk_dedicated_resources__affinity_group_id` FOREIGN KEY (`affinity_group_id`) REFERENCES `affinity_group`(`id`) ON DELETE CASCADE, INDEX `i_dedicated_resources_domain_id`(`domain_id`), INDEX `i_dedicated_resources_account_id`(`account_id`), + INDEX `i_dedicated_resources_affinity_group_id`(`affinity_group_id`), CONSTRAINT `uc_dedicated_resources__uuid` UNIQUE (`uuid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; @@ -486,9 +489,6 @@ ALTER TABLE `cloud`.`event` ADD COLUMN `archived` tinyint(1) unsigned NOT NULL D INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'alert.purge.interval', '86400', 'The interval (in seconds) to wait before running the alert purge thread'); INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'alert.purge.delay', '0', 'Alerts older than specified number days will be purged. Set this value to 0 to never delete alerts'); -INSERT INTO `cloud`.`dedicated_resources` (`data_center_id`, `domain_id`) SELECT `id`, `domain_id` FROM `cloud`.`data_center` WHERE `domain_id` IS NOT NULL; -UPDATE `cloud`.`data_center` SET `domain_id` = NULL WHERE `domain_id` IS NOT NULL; - DROP VIEW IF EXISTS `cloud`.`event_view`; CREATE VIEW `cloud`.`event_view` AS select