diff --git a/plugins/deployment-planners/user-dispersing/.classpath b/plugins/deployment-planners/user-dispersing/.classpath new file mode 100755 index 00000000000..a246f5e509f --- /dev/null +++ b/plugins/deployment-planners/user-dispersing/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/plugins/deployment-planners/user-dispersing/.project b/plugins/deployment-planners/user-dispersing/.project new file mode 100755 index 00000000000..d9b2d401aa8 --- /dev/null +++ b/plugins/deployment-planners/user-dispersing/.project @@ -0,0 +1,17 @@ + + + user-dispersing + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/plugins/deployment-planners/user-dispersing/.settings/org.eclipse.jdt.core.prefs b/plugins/deployment-planners/user-dispersing/.settings/org.eclipse.jdt.core.prefs new file mode 100755 index 00000000000..d0ee7df1827 --- /dev/null +++ b/plugins/deployment-planners/user-dispersing/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,12 @@ +#Tue Jun 19 15:34:37 PDT 2012 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/plugins/deployment-planners/user-dispersing/build.xml b/plugins/deployment-planners/user-dispersing/build.xml new file mode 100755 index 00000000000..ba72332586a --- /dev/null +++ b/plugins/deployment-planners/user-dispersing/build.xml @@ -0,0 +1,128 @@ + + + + + + + Cloud Stack ant build file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/deployment-planners/user-dispersing/src/com/cloud/deploy/UserDispersingPlanner.java b/plugins/deployment-planners/user-dispersing/src/com/cloud/deploy/UserDispersingPlanner.java new file mode 100755 index 00000000000..dcad1e70aff --- /dev/null +++ b/plugins/deployment-planners/user-dispersing/src/com/cloud/deploy/UserDispersingPlanner.java @@ -0,0 +1,215 @@ +// Copyright 2012 Citrix Systems, Inc. Licensed under the +// Apache License, Version 2.0 (the "License"); you may not use this +// file except in compliance with the License. Citrix Systems, Inc. +// reserves all rights not expressly granted by the License. +// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Automatically generated by addcopyright.py at 04/03/2012 +package com.cloud.deploy; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +import javax.ejb.Local; +import javax.naming.ConfigurationException; + +import org.apache.log4j.Logger; + +import com.cloud.configuration.Config; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.Pair; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineProfile; + +@Local(value=DeploymentPlanner.class) +public class UserDispersingPlanner extends FirstFitPlanner implements DeploymentPlanner { + + private static final Logger s_logger = Logger.getLogger(UserDispersingPlanner.class); + + /** + * This method should reorder the given list of Cluster Ids by applying any necessary heuristic + * for this planner + * For UserDispersingPlanner we need to order the clusters by considering the number of VMs for this account + * @return List ordered list of Cluster Ids + */ + @Override + protected List reorderClusters(long id, boolean isZone, Pair, Map> clusterCapacityInfo, VirtualMachineProfile vmProfile, DeploymentPlan plan){ + List clusterIdsByCapacity = clusterCapacityInfo.first(); + if(vmProfile.getOwner() == null){ + return clusterIdsByCapacity; + } + long accountId = vmProfile.getOwner().getAccountId(); + Pair, Map> clusterIdsVmCountInfo = listClustersByUserDispersion(id, isZone, accountId); + + //now we have 2 cluster lists - one ordered by capacity and the other by number of VMs for this account + //need to apply weights to these to find the correct ordering to follow + + if(_userDispersionWeight == 1.0f){ + List clusterIds = clusterIdsVmCountInfo.first(); + clusterIds.retainAll(clusterIdsByCapacity); + return clusterIds; + }else{ + //apply weights to the two lists + return orderByApplyingWeights(clusterCapacityInfo, clusterIdsVmCountInfo, accountId); + } + + + } + + /** + * This method should reorder the given list of Pod Ids by applying any necessary heuristic + * for this planner + * For UserDispersingPlanner we need to order the pods by considering the number of VMs for this account + * @return List ordered list of Pod Ids + */ + @Override + protected List reorderPods(Pair, Map> podCapacityInfo, VirtualMachineProfile vmProfile, DeploymentPlan plan){ + List podIdsByCapacity = podCapacityInfo.first(); + if(vmProfile.getOwner() == null){ + return podIdsByCapacity; + } + long accountId = vmProfile.getOwner().getAccountId(); + + Pair, Map> podIdsVmCountInfo = listPodsByUserDispersion(plan.getDataCenterId(), accountId); + + //now we have 2 pod lists - one ordered by capacity and the other by number of VMs for this account + //need to apply weights to these to find the correct ordering to follow + + if(_userDispersionWeight == 1.0f){ + List podIds = podIdsVmCountInfo.first(); + podIds.retainAll(podIdsByCapacity); + return podIds; + }else{ + //apply weights to the two lists + return orderByApplyingWeights(podCapacityInfo, podIdsVmCountInfo, accountId); + } + + } + + protected Pair, Map> listClustersByUserDispersion(long id, boolean isZone, long accountId){ + if (s_logger.isDebugEnabled()) { + s_logger.debug("Applying Userdispersion heuristic to clusters for account: "+ accountId); + } + Pair, Map> clusterIdsVmCountInfo; + if(isZone){ + clusterIdsVmCountInfo = _vmInstanceDao.listClusterIdsInZoneByVmCount(id, accountId); + }else{ + clusterIdsVmCountInfo = _vmInstanceDao.listClusterIdsInPodByVmCount(id, accountId); + } + if (s_logger.isTraceEnabled()) { + s_logger.trace("List of clusters in ascending order of number of VMs: "+ clusterIdsVmCountInfo.first()); + } + return clusterIdsVmCountInfo; + } + + protected Pair, Map> listPodsByUserDispersion(long dataCenterId, long accountId) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Applying Userdispersion heuristic to pods for account: "+ accountId); + } + Pair, Map> podIdsVmCountInfo = _vmInstanceDao.listPodIdsInZoneByVmCount(dataCenterId, accountId); + if (s_logger.isTraceEnabled()) { + s_logger.trace("List of pods in ascending order of number of VMs: "+ podIdsVmCountInfo.first()); + } + + return podIdsVmCountInfo; + } + + + private List orderByApplyingWeights(Pair, Map> capacityInfo, Pair, Map> vmCountInfo, long accountId){ + List capacityOrderedIds = capacityInfo.first(); + List vmCountOrderedIds = vmCountInfo.first(); + Map capacityMap = capacityInfo.second(); + Map vmCountMap = vmCountInfo.second(); + + if (s_logger.isTraceEnabled()) { + s_logger.trace("Capacity Id list: "+ capacityOrderedIds + " , capacityMap:"+capacityMap); + } + if (s_logger.isTraceEnabled()) { + s_logger.trace("Vm Count Id list: "+ vmCountOrderedIds + " , vmCountMap:"+vmCountMap); + } + + + List idsReorderedByWeights = new ArrayList(); + float capacityWeight = (1.0f -_userDispersionWeight); + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Applying userDispersionWeight: "+ _userDispersionWeight); + } + //normalize the vmCountMap + LinkedHashMap normalisedVmCountIdMap= new LinkedHashMap(); + + Long totalVmsOfAccount = _vmInstanceDao.countRunningByAccount(accountId); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Total VMs for account: "+ totalVmsOfAccount); + } + for(Long id : vmCountOrderedIds){ + Double normalisedCount = vmCountMap.get(id) / totalVmsOfAccount; + normalisedVmCountIdMap.put(id, normalisedCount); + } + + //consider only those ids that are in capacity map. + + SortedMap> sortedMap= new TreeMap>(); + for(Long id : capacityOrderedIds){ + Double weightedCapacityValue = capacityMap.get(id) * capacityWeight; + Double weightedVmCountValue = normalisedVmCountIdMap.get(id) * _userDispersionWeight; + Double totalWeight = weightedCapacityValue + weightedVmCountValue; + if(sortedMap.containsKey(totalWeight)){ + List idList = sortedMap.get(totalWeight); + idList.add(id); + sortedMap.put(totalWeight, idList); + }else{ + List idList = new ArrayList(); + idList.add(id); + sortedMap.put(totalWeight, idList); + } + } + + for(List idList : sortedMap.values()){ + idsReorderedByWeights.addAll(idList); + } + + if (s_logger.isTraceEnabled()) { + s_logger.trace("Reordered Id list: "+ idsReorderedByWeights); + } + + return idsReorderedByWeights; + } + + + @Override + public boolean canHandle(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid) { + if(vm.getHypervisorType() != HypervisorType.BareMetal){ + //check the allocation strategy + if (_allocationAlgorithm != null && _allocationAlgorithm.equals(AllocationAlgorithm.userdispersing.toString())) { + return true; + } + } + return false; + } + + float _userDispersionWeight; + + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + super.configure(name, params); + + String weight = _configDao.getValue(Config.VmUserDispersionWeight.key()); + _userDispersionWeight = NumbersUtil.parseFloat(weight, 1.0f); + + + return true; + } + +}