Updated Branches: refs/heads/master d2abc0e27 -> 6e48383ef
moved out user dispsersing deployment planner Project: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/commit/6e48383e Tree: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/tree/6e48383e Diff: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/diff/6e48383e Branch: refs/heads/master Commit: 6e48383ef8f9f44c0076277c90ff2d3e882926b7 Parents: 04b92c9 Author: Alex Huang <[email protected]> Authored: Wed Jun 20 16:03:04 2012 -0700 Committer: Alex Huang <[email protected]> Committed: Wed Jun 20 16:08:51 2012 -0700 ---------------------------------------------------------------------- .../deployment-planners/user-dispersing/.classpath | 10 + .../deployment-planners/user-dispersing/.project | 17 ++ .../.settings/org.eclipse.jdt.core.prefs | 12 + .../deployment-planners/user-dispersing/build.xml | 128 +++++++++ .../com/cloud/deploy/UserDispersingPlanner.java | 215 +++++++++++++++ 5 files changed, 382 insertions(+), 0 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/6e48383e/plugins/deployment-planners/user-dispersing/.classpath ---------------------------------------------------------------------- diff --git a/plugins/deployment-planners/user-dispersing/.classpath b/plugins/deployment-planners/user-dispersing/.classpath new file mode 100755 index 0000000..a246f5e --- /dev/null +++ b/plugins/deployment-planners/user-dispersing/.classpath @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/> + <classpathentry combineaccessrules="false" kind="src" path="/api"/> + <classpathentry combineaccessrules="false" kind="src" path="/core"/> + <classpathentry combineaccessrules="false" kind="src" path="/server"/> + <classpathentry combineaccessrules="false" kind="src" path="/utils"/> + <classpathentry kind="output" path="bin"/> +</classpath> http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/6e48383e/plugins/deployment-planners/user-dispersing/.project ---------------------------------------------------------------------- diff --git a/plugins/deployment-planners/user-dispersing/.project b/plugins/deployment-planners/user-dispersing/.project new file mode 100755 index 0000000..d9b2d40 --- /dev/null +++ b/plugins/deployment-planners/user-dispersing/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>user-dispersing</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/6e48383e/plugins/deployment-planners/user-dispersing/.settings/org.eclipse.jdt.core.prefs ---------------------------------------------------------------------- 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 0000000..d0ee7df --- /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 http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/6e48383e/plugins/deployment-planners/user-dispersing/build.xml ---------------------------------------------------------------------- diff --git a/plugins/deployment-planners/user-dispersing/build.xml b/plugins/deployment-planners/user-dispersing/build.xml new file mode 100755 index 0000000..ba72332 --- /dev/null +++ b/plugins/deployment-planners/user-dispersing/build.xml @@ -0,0 +1,128 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + 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. +--> + + +<project name="Cloud Stack User Dispersing Deployment Planner" default="help" basedir="."> + <description> + Cloud Stack ant build file + </description> + + <dirname property="dp-user-dispersing.base.dir" file="${ant.file.Cloud Stack User Dispersing Deployment Planner}/"/> + <!-- This directory must be set --> + <property name="top.dir" location="${dp-user-dispersing.base.dir}/../../.."/> + <property name="build.dir" location="${top.dir}/build"/> + + <echo message="build.dir=${build.dir}; top.dir=${top.dir}; dp-user-dispersing.base.dir=${dp-user-dispersing.base.dir}"/> + + <!-- Import anything that the user wants to set--> + <!-- Import properties files and environment variables here --> + + <property environment="env" /> + + <condition property="build-cloud.properties.file" value="${build.dir}/override/build-cloud.properties" else="${build.dir}/build-cloud.properties"> + <available file="${build.dir}/override/build-cloud.properties" /> + </condition> + + <condition property="cloud.properties.file" value="${build.dir}/override/cloud.properties" else="${build.dir}/cloud.properties"> + <available file="${build.dir}/override/cloud.properties" /> + </condition> + + <condition property="override.file" value="${build.dir}/override/replace.properties" else="${build.dir}/replace.properties"> + <available file="${build.dir}/override/replace.properties" /> + </condition> + + <echo message="Using build parameters from ${build-cloud.properties.file}" /> + <property file="${build-cloud.properties.file}" /> + + <echo message="Using company info from ${cloud.properties.file}" /> + <property file="${cloud.properties.file}" /> + + <echo message="Using override file from ${override.file}" /> + <property file="${override.file}" /> + + <property file="${build.dir}/build.number" /> + + <!-- In case these didn't get defined in the build-cloud.properties --> + <property name="branding.name" value="default" /> + <property name="deprecation" value="off" /> + <property name="target.compat.version" value="1.6" /> + <property name="source.compat.version" value="1.6" /> + <property name="debug" value="true" /> + <property name="debuglevel" value="lines,source"/> + + <echo message="target.dir=${target.dir}; top.dir=${top.dir}"/> + <!-- directories for build and distribution --> + <property name="target.dir" location="${top.dir}/target" /> + <property name="classes.dir" location="${target.dir}/classes" /> + <property name="jar.dir" location="${target.dir}/jar" /> + <property name="dep.cache.dir" location="${target.dir}/dep-cache" /> + <property name="build.log" location="${target.dir}/ant_verbose.txt" /> + + <property name="deps.dir" location="${top.dir}/deps" /> + + <property name="dp-user-dispersing.jar" value="cloud-dp-user-dispersing.jar" /> + <property name="dp-user-dispersing-scripts.dir" location="${dp-user-dispersing.base.dir}/scripts" /> + + <import file="${build.dir}/build-common.xml"/> + + <echo message="target.dir=${target.dir}; top.dir=${top.dir}"/> + + <!-- This section needs to be replaced by some kind of dependency library--> + <path id="deps.classpath"> + <!--filelist files="${deps.classpath}" /--> + <fileset dir="${deps.dir}" erroronmissingdir="false"> + <include name="*.jar" /> + </fileset> + </path> + + <path id="cloudstack.classpath"> + <fileset dir="${jar.dir}"> + <include name="*.jar"/> + </fileset> + </path> + + <path id="dp-user-dispersing.classpath"> + <path refid="deps.classpath"/> + <path refid="cloudstack.classpath"/> + </path> + + <!-- This section needs to be replaced by some kind of dependency library--> + + + <target name="init" description="Initialize binaries directory"> + <mkdir dir="${classes.dir}/${dp-user-dispersing.jar}"/> + <mkdir dir="${jar.dir}"/> + </target> + + <target name="compile-dp-user-dispersing" depends="init" description="Compile dp-user-dispersing"> + <compile-java jar.name="${dp-user-dispersing.jar}" top.dir="${dp-user-dispersing.base.dir}" classpath="dp-user-dispersing.classpath" /> + </target> + + <target name="help" description="help"> + <echo level="info" message="This is the build file for dp-user-dispersing"/> + <echo level="info" message="You can do a build by doing ant build or clean by ant clean" /> + </target> + + <target name="clean-dp-user-dispersing"> + <delete dir="${classes.dir}/${dp-user-dispersing.jar}"/> + </target> + + <target name="build" depends="compile-dp-user-dispersing"/> + <target name="clean" depends="clean-dp-user-dispersing"/> + +</project> http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/6e48383e/plugins/deployment-planners/user-dispersing/src/com/cloud/deploy/UserDispersingPlanner.java ---------------------------------------------------------------------- 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 0000000..dcad1e7 --- /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<Long> ordered list of Cluster Ids + */ + @Override + protected List<Long> reorderClusters(long id, boolean isZone, Pair<List<Long>, Map<Long, Double>> clusterCapacityInfo, VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan){ + List<Long> clusterIdsByCapacity = clusterCapacityInfo.first(); + if(vmProfile.getOwner() == null){ + return clusterIdsByCapacity; + } + long accountId = vmProfile.getOwner().getAccountId(); + Pair<List<Long>, Map<Long, Double>> 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<Long> 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<Long> ordered list of Pod Ids + */ + @Override + protected List<Long> reorderPods(Pair<List<Long>, Map<Long, Double>> podCapacityInfo, VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan){ + List<Long> podIdsByCapacity = podCapacityInfo.first(); + if(vmProfile.getOwner() == null){ + return podIdsByCapacity; + } + long accountId = vmProfile.getOwner().getAccountId(); + + Pair<List<Long>, Map<Long, Double>> 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<Long> podIds = podIdsVmCountInfo.first(); + podIds.retainAll(podIdsByCapacity); + return podIds; + }else{ + //apply weights to the two lists + return orderByApplyingWeights(podCapacityInfo, podIdsVmCountInfo, accountId); + } + + } + + protected Pair<List<Long>, Map<Long, Double>> listClustersByUserDispersion(long id, boolean isZone, long accountId){ + if (s_logger.isDebugEnabled()) { + s_logger.debug("Applying Userdispersion heuristic to clusters for account: "+ accountId); + } + Pair<List<Long>, Map<Long, Double>> 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<List<Long>, Map<Long, Double>> listPodsByUserDispersion(long dataCenterId, long accountId) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Applying Userdispersion heuristic to pods for account: "+ accountId); + } + Pair<List<Long>, Map<Long, Double>> 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<Long> orderByApplyingWeights(Pair<List<Long>, Map<Long, Double>> capacityInfo, Pair<List<Long>, Map<Long, Double>> vmCountInfo, long accountId){ + List<Long> capacityOrderedIds = capacityInfo.first(); + List<Long> vmCountOrderedIds = vmCountInfo.first(); + Map<Long, Double> capacityMap = capacityInfo.second(); + Map<Long, Double> 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<Long> idsReorderedByWeights = new ArrayList<Long>(); + float capacityWeight = (1.0f -_userDispersionWeight); + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Applying userDispersionWeight: "+ _userDispersionWeight); + } + //normalize the vmCountMap + LinkedHashMap<Long, Double> normalisedVmCountIdMap= new LinkedHashMap<Long, Double>(); + + 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<Double, List<Long>> sortedMap= new TreeMap<Double, List<Long>>(); + 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<Long> idList = sortedMap.get(totalWeight); + idList.add(id); + sortedMap.put(totalWeight, idList); + }else{ + List<Long> idList = new ArrayList<Long>(); + idList.add(id); + sortedMap.put(totalWeight, idList); + } + } + + for(List<Long> idList : sortedMap.values()){ + idsReorderedByWeights.addAll(idList); + } + + if (s_logger.isTraceEnabled()) { + s_logger.trace("Reordered Id list: "+ idsReorderedByWeights); + } + + return idsReorderedByWeights; + } + + + @Override + public boolean canHandle(VirtualMachineProfile<? extends VirtualMachine> 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<String, Object> params) throws ConfigurationException { + super.configure(name, params); + + String weight = _configDao.getValue(Config.VmUserDispersionWeight.key()); + _userDispersionWeight = NumbersUtil.parseFloat(weight, 1.0f); + + + return true; + } + +}
