From de28812addef186ad6740582d3e31b7d1609c058 Mon Sep 17 00:00:00 2001 From: Nitin Mehta Date: Fri, 18 Oct 2013 15:22:25 -0700 Subject: [PATCH] CLOUDSTACK-4746: From functionality point of view following will be changes. -> Threshold will not be applied for vms undergoing HA process (say during host going down event). -> Threshold will not be applied for vms undergoing maintenance. -> Threshold will apply for stop-start vm "after" the skip.counting.hours (time till which we reserve the capacity for the stopped vm). Reason being stop-start is a user initiated action and we are giving a time window (skip.counting.hours) till which its guaranteed to start in the same cluster. After that time, threshold check applies bcz we still want to reserve the capacity for urgent situations like HA, putting host into maintenance rather than get it consumed in such user initiated actions. Signed off by : nitin mehta --- client/pom.xml | 5 ++ client/tomcatconf/applicationContext.xml.in | 5 ++ client/tomcatconf/componentContext.xml.in | 9 ++ .../tomcatconf/nonossComponentContext.xml.in | 9 ++ .../cloud/entity/api/VMEntityManagerImpl.java | 2 +- plugins/deployment-planners/ha/pom.xml | 29 +++++++ .../ha/src/com/cloud/deploy/HAPlanner.java | 21 +++++ .../cloud/deploy/SkipHeuresticsPlanner.java | 64 ++++++++++++++ plugins/pom.xml | 1 + .../deploy/DeploymentPlanningManager.java | 2 +- .../deploy/DeploymentPlanningManagerImpl.java | 87 ++++++++++--------- .../src/com/cloud/deploy/FirstFitPlanner.java | 7 +- .../cloud/ha/HighAvailabilityManagerImpl.java | 39 +++++++-- .../storage/StoragePoolAutomationImpl.java | 16 ++-- .../com/cloud/vm/VirtualMachineManager.java | 6 +- .../cloud/vm/VirtualMachineManagerImpl.java | 17 ++-- .../vm/snapshot/VMSnapshotManagerImpl.java | 2 +- .../vm/DeploymentPlanningManagerImplTest.java | 24 ++--- .../vm/MockVirtualMachineManagerImpl.java | 6 +- 19 files changed, 263 insertions(+), 88 deletions(-) create mode 100644 plugins/deployment-planners/ha/pom.xml create mode 100644 plugins/deployment-planners/ha/src/com/cloud/deploy/HAPlanner.java create mode 100644 plugins/deployment-planners/ha/src/com/cloud/deploy/SkipHeuresticsPlanner.java diff --git a/client/pom.xml b/client/pom.xml index 32a547187a4..0ee1114949b 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -145,6 +145,11 @@ cloud-plugin-planner-user-dispersing ${project.version} + + org.apache.cloudstack + cloud-plugin-planner-ha + ${project.version} + org.apache.cloudstack cloud-plugin-planner-user-concentrated-pod diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 4fb13c056fc..2cf97607fb6 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -720,6 +720,10 @@ + + + + @@ -728,6 +732,7 @@ + diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index 09b2261ab38..dbacb4b9439 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -189,6 +189,15 @@ + + + + + + + + + diff --git a/client/tomcatconf/nonossComponentContext.xml.in b/client/tomcatconf/nonossComponentContext.xml.in index 17cf99c8f2f..a9aba7ef554 100644 --- a/client/tomcatconf/nonossComponentContext.xml.in +++ b/client/tomcatconf/nonossComponentContext.xml.in @@ -289,6 +289,15 @@ + + + + + + + + + diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java b/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java index ffb7dc59473..2b713b71faa 100755 --- a/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java @@ -184,7 +184,7 @@ public class VMEntityManagerImpl implements VMEntityManager { while (true) { DeployDestination dest = null; try { - dest = _dpMgr.planDeployment(vmProfile, plan, exclude); + dest = _dpMgr.planDeployment(vmProfile, plan, exclude, null); } catch (AffinityConflictException e) { throw new CloudRuntimeException( "Unable to create deployment, affinity rules associted to the VM conflict"); diff --git a/plugins/deployment-planners/ha/pom.xml b/plugins/deployment-planners/ha/pom.xml new file mode 100644 index 00000000000..27bb750f769 --- /dev/null +++ b/plugins/deployment-planners/ha/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + cloud-plugin-planner-ha + Apache CloudStack Plugin - HA Planner + + org.apache.cloudstack + cloudstack-plugins + 4.2.1-SNAPSHOT + ../../pom.xml + + diff --git a/plugins/deployment-planners/ha/src/com/cloud/deploy/HAPlanner.java b/plugins/deployment-planners/ha/src/com/cloud/deploy/HAPlanner.java new file mode 100644 index 00000000000..d6278c5ab0c --- /dev/null +++ b/plugins/deployment-planners/ha/src/com/cloud/deploy/HAPlanner.java @@ -0,0 +1,21 @@ +// 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. +package com.cloud.deploy; + + +public interface HAPlanner extends DeploymentPlanner { +} diff --git a/plugins/deployment-planners/ha/src/com/cloud/deploy/SkipHeuresticsPlanner.java b/plugins/deployment-planners/ha/src/com/cloud/deploy/SkipHeuresticsPlanner.java new file mode 100644 index 00000000000..4669df58baf --- /dev/null +++ b/plugins/deployment-planners/ha/src/com/cloud/deploy/SkipHeuresticsPlanner.java @@ -0,0 +1,64 @@ +// 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. +package com.cloud.deploy; + +import com.cloud.deploy.DeploymentPlan; +import com.cloud.deploy.FirstFitPlanner; +import com.cloud.deploy.HAPlanner; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineProfile; +import org.apache.log4j.Logger; + + +import javax.ejb.Local; +import javax.naming.ConfigurationException; +import java.util.List; +import java.util.Map; + +@Local(value=HAPlanner.class) +public class SkipHeuresticsPlanner extends FirstFitPlanner implements HAPlanner { + private static final Logger s_logger = Logger.getLogger(SkipHeuresticsPlanner.class); + + + /** + * This method should remove the clusters crossing capacity threshold + * to avoid further vm allocation on it. + * + * In case of HA, we shouldn't consider this threshold as we have reserved the capacity for such emergencies. + */ + @Override + protected void removeClustersCrossingThreshold(List clusterListForVmAllocation, ExcludeList avoid, VirtualMachineProfile vmProfile, DeploymentPlan plan){ + if (s_logger.isDebugEnabled()) { + s_logger.debug("Deploying vm during HA process, so skipping disable threshold check"); + } + return; + } + + @Override + public boolean canHandle(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid) { + return true; + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + super.configure(name, params); + + return true; + + } + +} diff --git a/plugins/pom.xml b/plugins/pom.xml index db5e4f6845b..55d42971adc 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -40,6 +40,7 @@ deployment-planners/user-concentrated-pod deployment-planners/user-dispersing deployment-planners/implicit-dedication + deployment-planners/ha host-allocators/random dedicated-resources hypervisors/ovm diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManager.java b/server/src/com/cloud/deploy/DeploymentPlanningManager.java index 9458df2946f..b16961b6f0a 100644 --- a/server/src/com/cloud/deploy/DeploymentPlanningManager.java +++ b/server/src/com/cloud/deploy/DeploymentPlanningManager.java @@ -41,7 +41,7 @@ public interface DeploymentPlanningManager extends Manager { * */ DeployDestination planDeployment(VirtualMachineProfile vmProfile, DeploymentPlan plan, - ExcludeList avoids) throws InsufficientServerCapacityException, AffinityConflictException; + ExcludeList avoids, DeploymentPlanner planner) throws InsufficientServerCapacityException, AffinityConflictException; String finalizeReservation(DeployDestination plannedDestination, VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoids) diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java index 23622dc5e84..4c41cbb7b27 100644 --- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -31,7 +31,7 @@ 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.AffinityGroupVMMapVO; import org.apache.cloudstack.affinity.AffinityGroupVO; import org.apache.cloudstack.affinity.dao.AffinityGroupDao; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; @@ -56,11 +56,11 @@ import com.cloud.dc.ClusterDetailsVO; import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; -import com.cloud.dc.DedicatedResourceVO; +import com.cloud.dc.DedicatedResourceVO; import com.cloud.dc.Pod; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; -import com.cloud.dc.dao.DedicatedResourceDao; +import com.cloud.dc.dao.DedicatedResourceDao; import com.cloud.dc.dao.HostPodDao; import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.deploy.DeploymentPlanner.PlannerResourceUsage; @@ -68,7 +68,6 @@ 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; @@ -99,7 +98,7 @@ import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.DB; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; -import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.StateListener; import com.cloud.vm.DiskProfile; import com.cloud.vm.ReservationContext; @@ -173,7 +172,7 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy @Inject protected HostDao _hostDao; @Inject protected HostPodDao _podDao; @Inject protected ClusterDao _clusterDao; - @Inject protected DedicatedResourceDao _dedicatedDao; + @Inject protected DedicatedResourceDao _dedicatedDao; @Inject protected GuestOSDao _guestOSDao = null; @Inject protected GuestOSCategoryDao _guestOSCategoryDao = null; @Inject protected DiskOfferingDao _diskOfferingDao; @@ -207,13 +206,13 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy @Override public DeployDestination planDeployment(VirtualMachineProfile vmProfile, - DeploymentPlan plan, ExcludeList avoids) throws InsufficientServerCapacityException, + DeploymentPlan plan, ExcludeList avoids, DeploymentPlanner planner) throws InsufficientServerCapacityException, AffinityConflictException { // call affinitygroup chain VirtualMachine vm = vmProfile.getVirtualMachine(); long vmGroupCount = _affinityGroupVMMapDao.countAffinityGroupsForVm(vm.getId()); - DataCenter dc = _dcDao.findById(vm.getDataCenterId()); + DataCenter dc = _dcDao.findById(vm.getDataCenterId()); if (vmGroupCount > 0) { for (AffinityGroupProcessor processor : _affinityProcessors) { @@ -223,14 +222,14 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy 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()); } // call planners - //DataCenter dc = _dcDao.findById(vm.getDataCenterId()); + //DataCenter dc = _dcDao.findById(vm.getDataCenterId()); // check if datacenter is in avoid set if (avoids.shouldAvoid(dc)) { if (s_logger.isDebugEnabled()) { @@ -242,19 +241,21 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy ServiceOffering offering = vmProfile.getServiceOffering(); - String plannerName = offering.getDeploymentPlanner(); - if (plannerName == null) { - if (vm.getHypervisorType() == HypervisorType.BareMetal) { - plannerName = "BareMetalPlanner"; - } else { - plannerName = _configDao.getValue(Config.VmDeploymentPlanner.key()); + if(planner == null){ + String plannerName = offering.getDeploymentPlanner(); + if (plannerName == null) { + if (vm.getHypervisorType() == HypervisorType.BareMetal) { + plannerName = "BareMetalPlanner"; + } else { + plannerName = _configDao.getValue(Config.VmDeploymentPlanner.key()); + } } - } - DeploymentPlanner planner = null; - for (DeploymentPlanner plannerInList : _planners) { - if (plannerName.equals(plannerInList.getName())) { - planner = plannerInList; - break; + + for (DeploymentPlanner plannerInList : _planners) { + if (plannerName.equals(plannerInList.getName())) { + planner = plannerInList; + break; + } } } @@ -305,7 +306,7 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy List suitableHosts = new ArrayList(); suitableHosts.add(host); Pair> potentialResources = findPotentialDeploymentResources( - suitableHosts, suitableVolumeStoragePools, avoids, getPlannerUsage(planner,vmProfile, plan ,avoids)); + suitableHosts, suitableVolumeStoragePools, avoids, getPlannerUsage(planner,vmProfile, plan ,avoids)); if (potentialResources != null) { Pod pod = _podDao.findById(host.getPodId()); Cluster cluster = _clusterDao.findById(host.getClusterId()); @@ -359,13 +360,13 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy vmProfile, lastPlan, avoids, HostAllocator.RETURN_UPTO_ALL); Map> suitableVolumeStoragePools = result.first(); List readyAndReusedVolumes = result.second(); - + // choose the potential pool for this VM for this host if (!suitableVolumeStoragePools.isEmpty()) { List suitableHosts = new ArrayList(); suitableHosts.add(host); Pair> potentialResources = findPotentialDeploymentResources( - suitableHosts, suitableVolumeStoragePools, avoids, getPlannerUsage(planner,vmProfile, plan ,avoids)); + suitableHosts, suitableVolumeStoragePools, avoids, getPlannerUsage(planner,vmProfile, plan ,avoids)); if (potentialResources != null) { Pod pod = _podDao.findById(host.getPodId()); Cluster cluster = _clusterDao.findById(host.getClusterId()); @@ -415,7 +416,7 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy resetAvoidSet(plannerAvoidOutput, plannerAvoidInput); dest = checkClustersforDestination(clusterList, vmProfile, plan, avoids, dc, - getPlannerUsage(planner, vmProfile, plan, avoids), plannerAvoidOutput); + getPlannerUsage(planner, vmProfile, plan, avoids), plannerAvoidOutput); if (dest != null) { return dest; } @@ -450,7 +451,7 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy return dest; } - private void checkForNonDedicatedResources(VirtualMachineProfile vmProfile, DataCenter dc, ExcludeList avoids) { + private void checkForNonDedicatedResources(VirtualMachineProfile vmProfile, DataCenter dc, ExcludeList avoids) { boolean isExplicit = false; VirtualMachine vm = vmProfile.getVirtualMachine(); @@ -485,16 +486,16 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy } // 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) { - //add explicitly dedicated resources in avoidList - + // dedicated pod/cluster/host in avoid list + List vmGroupMappings = _affinityGroupVMMapDao.findByVmIdType(vm.getId(), "ExplicitDedication"); + + if (vmGroupMappings != null && !vmGroupMappings.isEmpty()){ + isExplicit = true; + } + + if (!isExplicit) { + //add explicitly dedicated resources in avoidList + List allPodsInDc = _podDao.listAllPods(dc.getId()); List allDedicatedPods = _dedicatedDao.listAllPods(); allPodsInDc.retainAll(allDedicatedPods); @@ -508,10 +509,10 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy List allHostsInDc = _hostDao.listAllHosts(dc.getId()); List allDedicatedHosts = _dedicatedDao.listAllHosts(); allHostsInDc.retainAll(allDedicatedHosts); - avoids.addHostList(allHostsInDc); - } - } - + avoids.addHostList(allHostsInDc); + } + } + private void resetAvoidSet(ExcludeList avoidSet, ExcludeList removeSet) { if (avoidSet.getDataCentersToAvoid() != null && removeSet.getDataCentersToAvoid() != null) { avoidSet.getDataCentersToAvoid().removeAll(removeSet.getDataCentersToAvoid()); @@ -530,9 +531,9 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy } } - private PlannerResourceUsage getPlannerUsage(DeploymentPlanner planner, VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoids) throws InsufficientServerCapacityException { + private PlannerResourceUsage getPlannerUsage(DeploymentPlanner planner, VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoids) throws InsufficientServerCapacityException { if (planner != null && planner instanceof DeploymentClusterPlanner) { - return ((DeploymentClusterPlanner) planner).getResourceUsage(vmProfile, plan, avoids); + return ((DeploymentClusterPlanner) planner).getResourceUsage(vmProfile, plan, avoids); } else { return DeploymentPlanner.PlannerResourceUsage.Shared; } diff --git a/server/src/com/cloud/deploy/FirstFitPlanner.java b/server/src/com/cloud/deploy/FirstFitPlanner.java index 7124de28d7b..16924cc3ffb 100755 --- a/server/src/com/cloud/deploy/FirstFitPlanner.java +++ b/server/src/com/cloud/deploy/FirstFitPlanner.java @@ -263,7 +263,12 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentClusterPla return capacityList; } - private void removeClustersCrossingThreshold(List clusterListForVmAllocation, ExcludeList avoid, + /** + * This method should remove the clusters crossing capacity threshold + * to avoid further vm allocation on it + * + */ + protected void removeClustersCrossingThreshold(List clusterListForVmAllocation, ExcludeList avoid, VirtualMachineProfile vmProfile, DeploymentPlan plan) { List capacityList = getCapacitiesForCheckingThreshold(); diff --git a/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java b/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java index 061304e9820..d3cf1485483 100755 --- a/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java +++ b/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java @@ -29,6 +29,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.deploy.HAPlanner; import org.apache.log4j.Logger; import org.apache.log4j.NDC; @@ -132,6 +133,14 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements HighAvai this._fenceBuilders = _fenceBuilders; } + List _haPlanners; + public List getHAPlanners() { + return _haPlanners; + } + public void setHAPlanners(List _haPlanners) { + this._haPlanners = _haPlanners; + } + @Inject AgentManager _agentMgr; @Inject @@ -530,8 +539,18 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements HighAvai if (_haTag != null) { params.put(VirtualMachineProfile.Param.HaTag, _haTag); } - VMInstanceVO started = _itMgr.advanceStart(vm, params, _accountMgr.getSystemUser(), _accountMgr.getSystemAccount()); + // First try starting the vm with its original planner, if it doesn't succeed send HAPlanner as its an emergency. + VMInstanceVO started = null; + try{ + started = _itMgr.advanceStart(vm, params, _accountMgr.getSystemUser(), _accountMgr.getSystemAccount(), null); + }finally { + // Send HAPlanner. + if(started == null){ + s_logger.warn("Failed to deploy vm " + vmId + " with original planner, sending HAPlanner"); + started = _itMgr.advanceStart(vm, params, _accountMgr.getSystemUser(), _accountMgr.getSystemAccount(), _haPlanners.get(0)); + } + } if (started != null) { s_logger.info("VM is now restarted: " + vmId + " on " + started.getHostId()); return null; @@ -571,11 +590,21 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements HighAvai work.setStep(Step.Migrating); _haDao.update(work.getId(), work); - if (!_itMgr.migrateAway(work.getType(), vmId, srcHostId)) { - s_logger.warn("Unable to migrate vm from " + srcHostId); - _resourceMgr.maintenanceFailed(srcHostId); + // First try starting the vm with its original planner, if it doesn't succeed send HAPlanner as its an emergency. + boolean result = false; + try { + result = _itMgr.migrateAway(work.getType(), vmId, srcHostId, null); + }finally{ + if(!result){ + s_logger.warn("Failed to deploy vm " + vmId + " with original planner, sending HAPlanner"); + if (!_itMgr.migrateAway(work.getType(), vmId, srcHostId, _haPlanners.get(0))) { + s_logger.warn("Unable to migrate vm from " + srcHostId); + _resourceMgr.maintenanceFailed(srcHostId); + } + } + return null; } - return null; + } catch (InsufficientServerCapacityException e) { s_logger.warn("Insufficient capacity for migrating a VM."); _resourceMgr.maintenanceFailed(srcHostId); diff --git a/server/src/com/cloud/storage/StoragePoolAutomationImpl.java b/server/src/com/cloud/storage/StoragePoolAutomationImpl.java index f6b39f1fe47..972128348e5 100644 --- a/server/src/com/cloud/storage/StoragePoolAutomationImpl.java +++ b/server/src/com/cloud/storage/StoragePoolAutomationImpl.java @@ -33,10 +33,8 @@ import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.ModifyStoragePoolCommand; import com.cloud.alert.AlertManager; -import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.Status; -import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ResourceManager; import com.cloud.server.ManagementServer; import com.cloud.storage.dao.StoragePoolHostDao; @@ -250,7 +248,7 @@ public class StoragePoolAutomationImpl implements StoragePoolAutomation { if (restart) { if (this.vmMgr.advanceStart(consoleProxy, null, user, - account) == null) { + account, null) == null) { String errorMsg = "There was an error starting the console proxy id: " + vmInstance.getId() + " on another storage pool, cannot enable primary storage maintenance"; @@ -298,7 +296,7 @@ public class StoragePoolAutomationImpl implements StoragePoolAutomation { } if (restart) { - if (vmMgr.advanceStart(secStrgVm, null, user, account) == null) { + if (vmMgr.advanceStart(secStrgVm, null, user, account, null) == null) { String errorMsg = "There was an error starting the ssvm id: " + vmInstance.getId() + " on another storage pool, cannot enable primary storage maintenance"; @@ -329,7 +327,7 @@ public class StoragePoolAutomationImpl implements StoragePoolAutomation { } if (restart) { - if (vmMgr.advanceStart(domR, null, user, account) == null) { + if (vmMgr.advanceStart(domR, null, user, account, null) == null) { String errorMsg = "There was an error starting the domain router id: " + vmInstance.getId() + " on another storage pool, cannot enable primary storage maintenance"; @@ -413,7 +411,7 @@ public class StoragePoolAutomationImpl implements StoragePoolAutomation { ConsoleProxyVO consoleProxy = _consoleProxyDao .findById(vmInstance.getId()); - if (vmMgr.advanceStart(consoleProxy, null, user, account) == null) { + if (vmMgr.advanceStart(consoleProxy, null, user, account, null) == null) { String msg = "There was an error starting the console proxy id: " + vmInstance.getId() + " on storage pool, cannot complete primary storage maintenance"; @@ -431,7 +429,7 @@ public class StoragePoolAutomationImpl implements StoragePoolAutomation { VirtualMachine.Type.SecondaryStorageVm)) { SecondaryStorageVmVO ssVm = _secStrgDao.findById(vmInstance .getId()); - if (vmMgr.advanceStart(ssVm, null, user, account) == null) { + if (vmMgr.advanceStart(ssVm, null, user, account, null) == null) { String msg = "There was an error starting the ssvm id: " + vmInstance.getId() + " on storage pool, cannot complete primary storage maintenance"; @@ -448,7 +446,7 @@ public class StoragePoolAutomationImpl implements StoragePoolAutomation { if (vmInstance.getType().equals( VirtualMachine.Type.DomainRouter)) { DomainRouterVO domR = _domrDao.findById(vmInstance.getId()); - if (vmMgr.advanceStart(domR, null, user, account) == null) { + if (vmMgr.advanceStart(domR, null, user, account, null) == null) { String msg = "There was an error starting the domR id: " + vmInstance.getId() + " on storage pool, cannot complete primary storage maintenance"; @@ -465,7 +463,7 @@ public class StoragePoolAutomationImpl implements StoragePoolAutomation { if (vmInstance.getType().equals(VirtualMachine.Type.User)) { UserVmVO userVm = userVmDao.findById(vmInstance.getId()); - if (vmMgr.advanceStart(userVm, null, user, account) == null) { + if (vmMgr.advanceStart(userVm, null, user, account, null) == null) { String msg = "There was an error starting the user vm id: " + vmInstance.getId() diff --git a/server/src/com/cloud/vm/VirtualMachineManager.java b/server/src/com/cloud/vm/VirtualMachineManager.java index 6320956b9b3..88d03fd716c 100644 --- a/server/src/com/cloud/vm/VirtualMachineManager.java +++ b/server/src/com/cloud/vm/VirtualMachineManager.java @@ -96,9 +96,9 @@ public interface VirtualMachineManager extends Manager { boolean stateTransitTo(VMInstanceVO vm, VirtualMachine.Event e, Long hostId) throws NoTransitionException; - T advanceStart(T vm, Map params, User caller, Account account) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, OperationTimedoutException; + T advanceStart(T vm, Map params, User caller, Account account, DeploymentPlanner planner) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, OperationTimedoutException; - T advanceStart(T vm, Map params, User caller, Account account, DeploymentPlan planToDeploy) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, OperationTimedoutException; + T advanceStart(T vm, Map params, User caller, Account account, DeploymentPlan planToDeploy, DeploymentPlanner planner) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, OperationTimedoutException; boolean advanceStop(T vm, boolean forced, User caller, Account account) throws ResourceUnavailableException, OperationTimedoutException, ConcurrentOperationException; @@ -108,7 +108,7 @@ public interface VirtualMachineManager extends Manager { boolean destroy(T vm, User caller, Account account) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException; - boolean migrateAway(VirtualMachine.Type type, long vmid, long hostId) throws InsufficientServerCapacityException, VirtualMachineMigrationException; + boolean migrateAway(VirtualMachine.Type type, long vmid, long hostId, DeploymentPlanner planner) throws InsufficientServerCapacityException, VirtualMachineMigrationException; T migrate(T vm, long srcHostId, DeployDestination dest) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException; diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index d46bbb0b319..31a45e610c3 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -74,7 +74,6 @@ import com.cloud.agent.api.StopCommand; import com.cloud.agent.api.to.DiskTO; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; -import com.cloud.agent.api.to.VolumeTO; import com.cloud.agent.manager.Commands; import com.cloud.agent.manager.allocator.HostAllocator; import com.cloud.alert.AlertManager; @@ -575,7 +574,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac public T start(T vm, Map params, User caller, Account account, DeploymentPlan planToDeploy) throws InsufficientCapacityException, ResourceUnavailableException { try { - return advanceStart(vm, params, caller, account, planToDeploy); + return advanceStart(vm, params, caller, account, planToDeploy, null); } catch (ConcurrentOperationException e) { throw new CloudRuntimeException("Unable to start a VM due to concurrent operation", e); } @@ -708,13 +707,13 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } @Override - public T advanceStart(T vm, Map params, User caller, Account account) throws InsufficientCapacityException, + public T advanceStart(T vm, Map params, User caller, Account account, DeploymentPlanner planner) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { - return advanceStart(vm, params, caller, account, null); + return advanceStart(vm, params, caller, account, null, planner); } @Override - public T advanceStart(T vm, Map params, User caller, Account account, DeploymentPlan planToDeploy) + public T advanceStart(T vm, Map params, User caller, Account account, DeploymentPlan planToDeploy, DeploymentPlanner planner) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { long vmId = vm.getId(); VirtualMachineGuru vmGuru = getVmGuru(vm); @@ -823,7 +822,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vm, template, offering, account, params); DeployDestination dest = null; try { - dest = _dpMgr.planDeployment(vmProfile, plan, avoids); + dest = _dpMgr.planDeployment(vmProfile, plan, avoids, planner); } catch (AffinityConflictException e2) { s_logger.warn("Unable to create deployment, affinity rules associted to the VM conflict", e2); throw new CloudRuntimeException( @@ -1876,7 +1875,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } @Override - public boolean migrateAway(VirtualMachine.Type vmType, long vmId, long srcHostId) throws InsufficientServerCapacityException, VirtualMachineMigrationException { + public boolean migrateAway(VirtualMachine.Type vmType, long vmId, long srcHostId, DeploymentPlanner planner) throws InsufficientServerCapacityException, VirtualMachineMigrationException { VirtualMachineGuru vmGuru = _vmGurus.get(vmType); VMInstanceVO vm = vmGuru.findById(vmId); if (vm == null) { @@ -1902,7 +1901,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac while (true) { try { - dest = _dpMgr.planDeployment(profile, plan, excludes); + dest = _dpMgr.planDeployment(profile, plan, excludes, planner); } catch (AffinityConflictException e2) { s_logger.warn("Unable to create deployment, affinity rules associted to the VM conflict", e2); throw new CloudRuntimeException( @@ -3156,7 +3155,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac DeployDestination dest = null; try { - dest = _dpMgr.planDeployment(profile, plan, excludes); + dest = _dpMgr.planDeployment(profile, plan, excludes, null); } catch (AffinityConflictException e2) { s_logger.warn("Unable to create deployment, affinity rules associted to the VM conflict", e2); throw new CloudRuntimeException( diff --git a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java index ce4626908ba..8e277165a41 100644 --- a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java +++ b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java @@ -713,7 +713,7 @@ public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotMana // start or stop VM first, if revert from stopped state to running state, or from running to stopped if(userVm.getState() == VirtualMachine.State.Stopped && vmSnapshotVo.getType() == VMSnapshot.Type.DiskAndMemory){ try { - vm = _itMgr.advanceStart(userVm, new HashMap(), callerUser, owner); + vm = _itMgr.advanceStart(userVm, new HashMap(), callerUser, owner, null); hostId = vm.getHostId(); } catch (Exception e) { s_logger.error("Start VM " + userVm.getInstanceName() + " before reverting failed due to " + e.getMessage()); diff --git a/server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java b/server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java index fbfeecc81df..7572f0e777a 100644 --- a/server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java +++ b/server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java @@ -40,7 +40,7 @@ import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenterVO; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; -import com.cloud.dc.dao.DedicatedResourceDao; +import com.cloud.dc.dao.DedicatedResourceDao; import com.cloud.dc.dao.HostPodDao; import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; @@ -116,9 +116,9 @@ public class DeploymentPlanningManagerImplTest { @Inject ClusterDao _clusterDao; - @Inject - DedicatedResourceDao _dedicatedDao; - + @Inject + DedicatedResourceDao _dedicatedDao; + private static long domainId = 5L; private static long dataCenterId = 1L; @@ -163,7 +163,7 @@ public class DeploymentPlanningManagerImplTest { DataCenterDeployment plan = new DataCenterDeployment(dataCenterId); Mockito.when(avoids.shouldAvoid((DataCenterVO) Mockito.anyObject())).thenReturn(true); - DeployDestination dest = _dpm.planDeployment(vmProfile, plan, avoids); + DeployDestination dest = _dpm.planDeployment(vmProfile, plan, avoids, null); assertNull("DataCenter is in avoid set, destination should be null! ", dest); } @@ -178,7 +178,7 @@ public class DeploymentPlanningManagerImplTest { Mockito.when(avoids.shouldAvoid((DataCenterVO) Mockito.anyObject())).thenReturn(false); Mockito.when(_planner.canHandle(vmProfile, plan, avoids)).thenReturn(false); - DeployDestination dest = _dpm.planDeployment(vmProfile, plan, avoids); + DeployDestination dest = _dpm.planDeployment(vmProfile, plan, avoids, null); assertNull("Planner cannot handle, destination should be null! ", dest); } @@ -193,7 +193,7 @@ public class DeploymentPlanningManagerImplTest { Mockito.when(_planner.canHandle(vmProfile, plan, avoids)).thenReturn(true); Mockito.when(((DeploymentClusterPlanner) _planner).orderClusters(vmProfile, plan, avoids)).thenReturn(null); - DeployDestination dest = _dpm.planDeployment(vmProfile, plan, avoids); + DeployDestination dest = _dpm.planDeployment(vmProfile, plan, avoids, null); assertNull("Planner cannot handle, destination should be null! ", dest); } @@ -258,11 +258,11 @@ public class DeploymentPlanningManagerImplTest { } @Bean - public DedicatedResourceDao dedicatedResourceDao() { - return Mockito.mock(DedicatedResourceDao.class); - } - - @Bean + public DedicatedResourceDao dedicatedResourceDao() { + return Mockito.mock(DedicatedResourceDao.class); + } + + @Bean public GuestOSDao guestOSDao() { return Mockito.mock(GuestOSDao.class); } diff --git a/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java b/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java index 14ef48b1118..7dd30d7a749 100755 --- a/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java +++ b/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java @@ -133,7 +133,7 @@ public class MockVirtualMachineManagerImpl extends ManagerBase implements Virtua } @Override - public boolean migrateAway(Type type, long vmid, long hostId) throws InsufficientServerCapacityException, VirtualMachineMigrationException { + public boolean migrateAway(Type type, long vmid, long hostId, DeploymentPlanner planner) throws InsufficientServerCapacityException, VirtualMachineMigrationException { // TODO Auto-generated method stub return false; } @@ -201,14 +201,14 @@ public class MockVirtualMachineManagerImpl extends ManagerBase implements Virtua } @Override - public T advanceStart(T vm, Map params, User caller, Account account) throws InsufficientCapacityException, ResourceUnavailableException, + public T advanceStart(T vm, Map params, User caller, Account account, DeploymentPlanner planner) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, OperationTimedoutException { // TODO Auto-generated method stub return null; } @Override - public T advanceStart(T vm, Map params, User caller, Account account, DeploymentPlan planToDeploy) throws InsufficientCapacityException, + public T advanceStart(T vm, Map params, User caller, Account account, DeploymentPlan planToDeploy, DeploymentPlanner planner) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, OperationTimedoutException { // TODO Auto-generated method stub return null;