Return-Path: X-Original-To: apmail-cloudstack-commits-archive@www.apache.org Delivered-To: apmail-cloudstack-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 736E910007 for ; Wed, 8 May 2013 23:42:57 +0000 (UTC) Received: (qmail 83934 invoked by uid 500); 8 May 2013 23:42:57 -0000 Delivered-To: apmail-cloudstack-commits-archive@cloudstack.apache.org Received: (qmail 83914 invoked by uid 500); 8 May 2013 23:42:57 -0000 Mailing-List: contact commits-help@cloudstack.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cloudstack.apache.org Delivered-To: mailing list commits@cloudstack.apache.org Received: (qmail 83907 invoked by uid 99); 8 May 2013 23:42:57 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 08 May 2013 23:42:57 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id DA93E88A28B; Wed, 8 May 2013 23:42:56 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: prachidamle@apache.org To: commits@cloudstack.apache.org Message-Id: <0cdda18a4181493dbb6798a684123309@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: git commit: updated refs/heads/planner_reserve to 0e792eb Date: Wed, 8 May 2013 23:42:56 +0000 (UTC) Updated Branches: refs/heads/planner_reserve 81d6da5ad -> 0e792eb93 - Host reservation release process - Make deployment_planner optional field in service offering, global config vm.deployment.planner - Admin API to release host reservation Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/0e792eb9 Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/0e792eb9 Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/0e792eb9 Branch: refs/heads/planner_reserve Commit: 0e792eb938d6e5af7a3d0324ba61fc11f4011a46 Parents: 81d6da5 Author: Prachi Damle Authored: Wed May 8 16:38:01 2013 -0700 Committer: Prachi Damle Committed: Wed May 8 16:38:01 2013 -0700 ---------------------------------------------------------------------- api/src/com/cloud/event/EventTypes.java | 3 + api/src/com/cloud/resource/ResourceService.java | 4 +- .../admin/host/ReleaseHostReservationCmd.java | 105 +++++++ .../admin/offering/CreateServiceOfferingCmd.java | 2 +- client/tomcatconf/commands.properties.in | 1 + .../com/cloud/capacity/CapacityManagerImpl.java | 33 ++- server/src/com/cloud/configuration/Config.java | 3 + .../deploy/DeploymentPlanningManagerImpl.java | 239 +++++++++++---- server/src/com/cloud/deploy/FirstFitPlanner.java | 8 +- .../deploy/dao/PlannerHostReservationDao.java | 4 + .../deploy/dao/PlannerHostReservationDaoImpl.java | 13 + .../com/cloud/resource/ResourceManagerImpl.java | 43 +++ .../src/com/cloud/server/ManagementServerImpl.java | 1 + .../src/com/cloud/service/ServiceOfferingVO.java | 11 +- .../src/com/cloud/upgrade/dao/Upgrade410to420.java | 10 +- server/src/com/cloud/vm/UserVmManagerImpl.java | 3 + server/src/com/cloud/vm/dao/VMInstanceDao.java | 28 +- server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java | 147 ++++++---- .../cloud/resource/MockResourceManagerImpl.java | 6 + setup/db/db/schema-410to420.sql | 5 +- 20 files changed, 510 insertions(+), 159 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0e792eb9/api/src/com/cloud/event/EventTypes.java ---------------------------------------------------------------------- diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index 0ee7f40..f9a0c04 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -390,6 +390,8 @@ public class EventTypes { public static final String EVENT_AFFINITY_GROUP_REMOVE = "AG.REMOVE"; public static final String EVENT_VM_AFFINITY_GROUP_UPDATE = "VM.AG.UPDATE"; + public static final String EVENT_HOST_RESERVATION_RELEASE = "HOST.RESERVATION.RELEASE"; + static { // TODO: need a way to force author adding event types to declare the entity details as well, with out braking @@ -690,6 +692,7 @@ public class EventTypes { entityEventDetails.put(EVENT_AUTOSCALEVMGROUP_UPDATE, AutoScaleVmGroup.class.getName()); entityEventDetails.put(EVENT_AUTOSCALEVMGROUP_ENABLE, AutoScaleVmGroup.class.getName()); entityEventDetails.put(EVENT_AUTOSCALEVMGROUP_DISABLE, AutoScaleVmGroup.class.getName()); + } public static String getEntityForEvent (String eventName) { http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0e792eb9/api/src/com/cloud/resource/ResourceService.java ---------------------------------------------------------------------- diff --git a/api/src/com/cloud/resource/ResourceService.java b/api/src/com/cloud/resource/ResourceService.java index 08e2585..ce0df63 100755 --- a/api/src/com/cloud/resource/ResourceService.java +++ b/api/src/com/cloud/resource/ResourceService.java @@ -100,11 +100,13 @@ public interface ResourceService { Swift discoverSwift(AddSwiftCmd addSwiftCmd) throws DiscoveryException; S3 discoverS3(AddS3Cmd cmd) throws DiscoveryException; - + List getSupportedHypervisorTypes(long zoneId, boolean forVirtualRouter, Long podId); Pair, Integer> listSwifts(ListSwiftsCmd cmd); List listS3s(ListS3sCmd cmd); + boolean releaseHostReservation(Long hostId); + } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0e792eb9/api/src/org/apache/cloudstack/api/command/admin/host/ReleaseHostReservationCmd.java ---------------------------------------------------------------------- diff --git a/api/src/org/apache/cloudstack/api/command/admin/host/ReleaseHostReservationCmd.java b/api/src/org/apache/cloudstack/api/command/admin/host/ReleaseHostReservationCmd.java new file mode 100644 index 0000000..d09cf38 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/host/ReleaseHostReservationCmd.java @@ -0,0 +1,105 @@ +// 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 org.apache.cloudstack.api.command.admin.host; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.HostResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.log4j.Logger; + +import com.cloud.async.AsyncJob; +import com.cloud.event.EventTypes; +import com.cloud.user.Account; +import com.cloud.user.UserContext; + +@APICommand(name = "releaseHostReservation", description = "Releases host reservation.", responseObject = SuccessResponse.class) +public class ReleaseHostReservationCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(ReleaseHostReservationCmd.class.getName()); + + private static final String s_name = "releasehostreservationresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=HostResponse.class, + required=true, description="the host ID") + private Long id; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + Account account = UserContext.current().getCaller(); + if (account != null) { + return account.getId(); + } + + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public String getEventType() { + return EventTypes.EVENT_HOST_RESERVATION_RELEASE; + } + + @Override + public String getEventDescription() { + return "releasing reservation for host: " + getId(); + } + + @Override + public AsyncJob.Type getInstanceType() { + return AsyncJob.Type.Host; + } + + @Override + public Long getInstanceId() { + return getId(); + } + + @Override + public void execute(){ + boolean result = _resourceService.releaseHostReservation(getId()); + if (result) { + SuccessResponse response = new SuccessResponse(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to release host reservation"); + } + } +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0e792eb9/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java ---------------------------------------------------------------------- diff --git a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java index 74392cd..c155b70 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java @@ -84,7 +84,7 @@ public class CreateServiceOfferingCmd extends BaseCmd { @Parameter(name=ApiConstants.NETWORKRATE, type=CommandType.INTEGER, description="data transfer rate in megabits per second allowed. Supported only for non-System offering and system offerings having \"domainrouter\" systemvmtype") private Integer networkRate; - @Parameter(name = ApiConstants.DEPLOYMENT_PLANNER, type = CommandType.STRING, description = "The deployment planner heuristics used to deploy a VM of this offering, default \"FirstFitPlanner\".") + @Parameter(name = ApiConstants.DEPLOYMENT_PLANNER, type = CommandType.STRING, description = "The deployment planner heuristics used to deploy a VM of this offering. If null, value of global config vm.deployment.planner is used") private String deploymentPlanner; ///////////////////////////////////////////////////// http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0e792eb9/client/tomcatconf/commands.properties.in ---------------------------------------------------------------------- diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index bd9b897..7f62603 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -259,6 +259,7 @@ listHosts=3 findHostsForMigration=1 addSecondaryStorage=1 updateHostPassword=1 +releaseHostReservation=1 #### volume commands attachVolume=15 http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0e792eb9/server/src/com/cloud/capacity/CapacityManagerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/capacity/CapacityManagerImpl.java b/server/src/com/cloud/capacity/CapacityManagerImpl.java index 9a1e972..9e4bb22 100755 --- a/server/src/com/cloud/capacity/CapacityManagerImpl.java +++ b/server/src/com/cloud/capacity/CapacityManagerImpl.java @@ -82,11 +82,14 @@ import com.cloud.utils.db.DB; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; import com.cloud.utils.fsm.StateListener; +import com.cloud.vm.UserVmDetailVO; +import com.cloud.vm.UserVmVO; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Event; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.UserVmDetailsDao; import com.cloud.vm.dao.VMInstanceDao; import com.cloud.vm.snapshot.VMSnapshot; import com.cloud.vm.snapshot.VMSnapshotVO; @@ -126,6 +129,8 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, protected VMSnapshotDao _vmSnapshotDao; @Inject protected UserVmDao _userVMDao; + @Inject + protected UserVmDetailsDao _userVmDetailsDao; @Inject ClusterDetailsDao _clusterDetailsDao; @@ -140,6 +145,8 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, @Inject MessageBus _messageBus; + private static final String MESSAGE_RESERVED_CAPACITY_FREED_FLAG = "Message.ReservedCapacityFreed.Flag"; + @Override public boolean configure(String name, Map params) throws ConfigurationException { _vmCapacityReleaseInterval = NumbersUtil.parseInt(_configDao.getValue(Config.CapacitySkipcountingHours.key()), 3600); @@ -561,9 +568,19 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, reservedMemory += so.getRamSize() * 1024L * 1024L; reservedCpu += so.getCpu() * so.getSpeed(); } else { - // signal that the VM has been stopped for skip.counting.hours, + // signal if not done already, that the VM has been stopped for skip.counting.hours, // hence capacity will not be reserved anymore. - _messageBus.publish(_name, "VM_ReservedCapacity_Free", PublishScope.LOCAL, vm); + UserVmDetailVO messageSentFlag = _userVmDetailsDao.findDetail(vm.getId(), MESSAGE_RESERVED_CAPACITY_FREED_FLAG); + if (messageSentFlag == null || !Boolean.valueOf(messageSentFlag.getValue())) { + _messageBus.publish(_name, "VM_ReservedCapacity_Free", PublishScope.LOCAL, vm); + + if (vm.getType() == VirtualMachine.Type.User) { + UserVmVO userVM = _userVMDao.findById(vm.getId()); + _userVMDao.loadDetails(userVM); + userVM.setDetail(MESSAGE_RESERVED_CAPACITY_FREED_FLAG, "true"); + _userVMDao.saveDetails(userVM); + } + } } } @@ -700,6 +717,18 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, allocateVmCapacity(vm, fromLastHost); } + if (newState == State.Stopped) { + if (vm.getType() == VirtualMachine.Type.User) { + + UserVmVO userVM = _userVMDao.findById(vm.getId()); + _userVMDao.loadDetails(userVM); + // free the message sent flag if it exists + userVM.setDetail(MESSAGE_RESERVED_CAPACITY_FREED_FLAG, "false"); + _userVMDao.saveDetails(userVM); + + } + } + return true; } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0e792eb9/server/src/com/cloud/configuration/Config.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index 1f0a1a9..dea8807 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -214,6 +214,8 @@ public enum Config { SecStorageProxy("Advanced", AgentManager.class, String.class, "secstorage.proxy", null, "http proxy used by ssvm, in http://username:password@proxyserver:port format", null), AlertPurgeInterval("Advanced", ManagementServer.class, Integer.class, "alert.purge.interval", "86400", "The interval (in seconds) to wait before running the alert purge thread", null), AlertPurgeDelay("Advanced", ManagementServer.class, Integer.class, "alert.purge.delay", "0", "Alerts older than specified number days will be purged. Set this value to 0 to never delete alerts", null), + HostReservationReleasePeriod("Advanced", ManagementServer.class, Integer.class, "host.reservation.release.period", "300000", "The interval in milliseconds between host reservation release checks", null), + // LB HealthCheck Interval. LBHealthCheck("Advanced", ManagementServer.class, String.class, "healthcheck.update.interval", "600", @@ -235,6 +237,7 @@ public enum Config { ApplyAllocationAlgorithmToPods("Advanced", ManagementServer.class, Boolean.class, "apply.allocation.algorithm.to.pods", "false", "If true, deployment planner applies the allocation heuristics at pods first in the given datacenter during VM resource allocation", "true,false"), VmUserDispersionWeight("Advanced", ManagementServer.class, Float.class, "vm.user.dispersion.weight", "1", "Weight for user dispersion heuristic (as a value between 0 and 1) applied to resource allocation during vm deployment. Weight for capacity heuristic will be (1 - weight of user dispersion)", null), VmAllocationAlgorithm("Advanced", ManagementServer.class, String.class, "vm.allocation.algorithm", "random", "'random', 'firstfit', 'userdispersing', 'userconcentratedpod_random', 'userconcentratedpod_firstfit' : Order in which hosts within a cluster will be considered for VM/volume allocation.", null), + VmDeploymentPlanner("Advanced", ManagementServer.class, String.class, "vm.deployment.planner", "FirstFitPlanner", "'FirstFitPlanner', 'UserDispersingPlanner', 'UserConcentratedPodPlanner': DeploymentPlanner heuristic that will be used for VM deployment.", null), EndpointeUrl("Advanced", ManagementServer.class, String.class, "endpointe.url", "http://localhost:8080/client/api", "Endpointe Url", null), ElasticLoadBalancerEnabled("Advanced", ManagementServer.class, String.class, "network.loadbalancer.basiczone.elb.enabled", "false", "Whether the load balancing service is enabled for basic zones", "true,false"), ElasticLoadBalancerNetwork("Advanced", ManagementServer.class, String.class, "network.loadbalancer.basiczone.elb.network", "guest", "Whether the elastic load balancing service public ips are taken from the public or guest network", "guest,public"), http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0e792eb9/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java index b05d065..5af17d2 100644 --- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -21,7 +21,8 @@ import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; import java.util.TreeSet; import javax.ejb.Local; @@ -29,7 +30,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import org.apache.cloudstack.affinity.AffinityGroupProcessor; -import org.apache.cloudstack.affinity.AffinityGroupVMMapVO; + import org.apache.cloudstack.affinity.dao.AffinityGroupDao; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; @@ -41,9 +42,10 @@ import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; -import com.cloud.capacity.Capacity; + import com.cloud.capacity.CapacityManager; import com.cloud.capacity.dao.CapacityDao; +import com.cloud.cluster.ManagementServerNode; import com.cloud.configuration.Config; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.ClusterDetailsDao; @@ -65,7 +67,6 @@ import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.network.security.SecurityGroupVO; import com.cloud.offering.ServiceOffering; import com.cloud.org.Cluster; import com.cloud.org.Grouping; @@ -82,6 +83,7 @@ import com.cloud.storage.dao.GuestOSDao; import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.storage.dao.VolumeDao; import com.cloud.user.AccountManager; +import com.cloud.utils.DateUtil; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.component.ComponentContext; @@ -94,6 +96,7 @@ import com.cloud.vm.ReservationContext; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; import com.cloud.agent.AgentManager; @@ -106,6 +109,7 @@ import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupRoutingCommand; import com.cloud.agent.manager.allocator.HostAllocator; + @Local(value = { DeploymentPlanningManager.class }) public class DeploymentPlanningManagerImpl extends ManagerBase implements DeploymentPlanningManager, Manager, Listener { @@ -124,9 +128,14 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy DataCenterDao _dcDao; @Inject PlannerHostReservationDao _plannerHostReserveDao; - + private int _vmCapacityReleaseInterval; @Inject MessageBus _messageBus; + private Timer _timer = null; + private long _hostReservationReleasePeriod = 60L * 60L * 1000L; // one hour by default + + private static final long INITIAL_RESERVATION_RELEASE_CHECKER_DELAY = 30L * 1000L; // thirty seconds expressed in milliseconds + protected long _nodeId = -1; protected List _storagePoolAllocators; public List getStoragePoolAllocators() { @@ -212,7 +221,11 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy ServiceOffering offering = vmProfile.getServiceOffering(); - DeploymentPlanner planner = ComponentContext.getComponent(offering.getDeploymentPlanner()); + String plannerName = offering.getDeploymentPlanner(); + if (plannerName == null) { + plannerName = _configDao.getValue(Config.VmDeploymentPlanner.key()); + } + DeploymentPlanner planner = ComponentContext.getComponent(plannerName); int cpu_requested = offering.getCpu() * offering.getSpeed(); long ram_requested = offering.getRamSize() * 1024L * 1024L; @@ -352,58 +365,58 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy DeployDestination dest = null; List clusterList = null; - if (offering != null && offering.getDeploymentPlanner() != null) { - if (planner != null && planner.canHandle(vmProfile, plan, avoids)) { - while (true) { + if (planner != null && planner.canHandle(vmProfile, plan, avoids)) { + while (true) { - if (planner instanceof DeploymentClusterPlanner) { + if (planner instanceof DeploymentClusterPlanner) { - ExcludeList PlannerAvoidInput = new ExcludeList(avoids.getDataCentersToAvoid(), - avoids.getPodsToAvoid(), avoids.getClustersToAvoid(), avoids.getHostsToAvoid(), - avoids.getPoolsToAvoid()); + ExcludeList PlannerAvoidInput = new ExcludeList(avoids.getDataCentersToAvoid(), + avoids.getPodsToAvoid(), avoids.getClustersToAvoid(), avoids.getHostsToAvoid(), + avoids.getPoolsToAvoid()); - clusterList = ((DeploymentClusterPlanner) planner).orderClusters(vmProfile, plan, avoids); + clusterList = ((DeploymentClusterPlanner) planner).orderClusters(vmProfile, plan, avoids); - if (clusterList != null && !clusterList.isEmpty()) { - // planner refactoring. call allocators to list hosts - ExcludeList PlannerAvoidOutput = new ExcludeList(avoids.getDataCentersToAvoid(), - avoids.getPodsToAvoid(), avoids.getClustersToAvoid(), avoids.getHostsToAvoid(), - avoids.getPoolsToAvoid()); + if (clusterList != null && !clusterList.isEmpty()) { + // planner refactoring. call allocators to list hosts + ExcludeList PlannerAvoidOutput = new ExcludeList(avoids.getDataCentersToAvoid(), + avoids.getPodsToAvoid(), avoids.getClustersToAvoid(), avoids.getHostsToAvoid(), + avoids.getPoolsToAvoid()); - resetAvoidSet(PlannerAvoidOutput, PlannerAvoidInput); + resetAvoidSet(PlannerAvoidOutput, PlannerAvoidInput); - dest = checkClustersforDestination(clusterList, vmProfile, plan, avoids, dc, - getPlannerUsage(planner), PlannerAvoidOutput); - if(dest != null){ - return dest; - } - // reset the avoid input to the planners - resetAvoidSet(avoids, PlannerAvoidOutput); + dest = checkClustersforDestination(clusterList, vmProfile, plan, avoids, dc, + getPlannerUsage(planner), PlannerAvoidOutput); + if (dest != null) { + return dest; + } + // reset the avoid input to the planners + resetAvoidSet(avoids, PlannerAvoidOutput); + } else { + return null; + } + } else { + dest = planner.plan(vmProfile, plan, avoids); + if (dest != null) { + long hostId = dest.getHost().getId(); + avoids.addHost(dest.getHost().getId()); + + if (checkIfHostFitsPlannerUsage(hostId, DeploymentPlanner.PlannerResourceUsage.Shared)) { + // found destination + return dest; } else { - return null; + // find another host - seems some concurrent + // deployment picked it up for dedicated access + continue; } } else { - dest = planner.plan(vmProfile, plan, avoids); - if (dest != null) { - long hostId = dest.getHost().getId(); - avoids.addHost(dest.getHost().getId()); - - if (checkIfHostFitsPlannerUsage(hostId, DeploymentPlanner.PlannerResourceUsage.Shared)) { - // found destination - return dest; - } else { - // find another host - seems some concurrent deployment picked it up for dedicated access - continue; - } - }else{ - return null; - } + return null; } } } } + return dest; } @@ -495,36 +508,69 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy } @DB - public void checkHostReservationRelease(VMInstanceVO vm) { - s_logger.debug("MessageBus message: host reserved capacity released for VM: " + vm.getLastHostId() - + ", checking if host reservation can be released for host:" + vm.getLastHostId()); - - Long hostId = vm.getLastHostId(); + public boolean checkHostReservationRelease(Long hostId) { if (hostId != null) { - List vms = _vmInstanceDao.listUpByHostId(hostId); - if (vms.size() > 0) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Cannot release reservation, Found " + vms.size() + " VMs Running on host " + hostId); + PlannerHostReservationVO reservationEntry = _plannerHostReserveDao.findByHostId(hostId); + if (reservationEntry != null && reservationEntry.getResourceUsage() != null) { + + // check if any VMs are starting or running on this host + List vms = _vmInstanceDao.listUpByHostId(hostId); + if (vms.size() > 0) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Cannot release reservation, Found " + vms.size() + " VMs Running on host " + + hostId); + } + return false; } - } - List vmsByLastHostId = _vmInstanceDao.listByLastHostId(hostId); - if (vmsByLastHostId.size() > 0) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Cannot release reservation, Found " + vmsByLastHostId.size() - + " VMs Stopped but reserved on host " + hostId); + List vmsByLastHostId = _vmInstanceDao.listByLastHostId(hostId); + if (vmsByLastHostId.size() > 0) { + // check if any VMs are within skip.counting.hours, if yes + // we + // cannot release the host + for (VMInstanceVO stoppedVM : vmsByLastHostId) { + long secondsSinceLastUpdate = (DateUtil.currentGMTTime().getTime() - stoppedVM.getUpdateTime() + .getTime()) / 1000; + if (secondsSinceLastUpdate < _vmCapacityReleaseInterval) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Cannot release reservation, Found VM: " + stoppedVM + + " Stopped but reserved on host " + hostId); + } + return false; + } + } } - } - if (s_logger.isDebugEnabled()) { - s_logger.debug("Host has no VMs, releasing the planner reservation"); - } + // check if any VMs are stopping on or migrating to this host + List vmsStoppingMigratingByHostId = _vmInstanceDao.findByHostInStates(hostId, + State.Stopping, State.Migrating, State.Starting); + if (vmsStoppingMigratingByHostId.size() > 0) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Cannot release reservation, Found " + vms.size() + + " VMs stopping/migrating on host " + hostId); + } + return false; + } - PlannerHostReservationVO reservationEntry = _plannerHostReserveDao.findByHostId(hostId); - if (reservationEntry != null) { - long id = reservationEntry.getId(); + // check if any VMs are in starting state with no hostId set yet + // - + // just ignore host release to avoid race condition + List vmsStartingNoHost = _vmInstanceDao.listStartingWithNoHostId(); + + if (vmsStartingNoHost.size() > 0) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Cannot release reservation, Found " + vms.size() + + " VMs starting as of now and no hostId yet stored"); + } + return false; + } + if (s_logger.isDebugEnabled()) { + s_logger.debug("Host has no VMs associated, releasing the planner reservation for host " + hostId); + } + + long id = reservationEntry.getId(); final Transaction txn = Transaction.currentTxn(); try { @@ -533,11 +579,13 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy final PlannerHostReservationVO lockedEntry = _plannerHostReserveDao.lockRow(id, true); if (lockedEntry == null) { s_logger.error("Unable to lock the host entry for reservation, host: " + hostId); + return false; } // check before updating if (lockedEntry.getResourceUsage() != null) { lockedEntry.setResourceUsage(null); _plannerHostReserveDao.persist(lockedEntry); + return true; } } finally { txn.commit(); @@ -545,6 +593,32 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy } } + return false; + } + + class HostReservationReleaseChecker extends TimerTask { + @Override + public void run() { + try { + s_logger.debug("Checking if any host reservation can be released ... "); + checkHostReservations(); + s_logger.debug("Done running HostReservationReleaseChecker ... "); + } catch (Throwable t) { + s_logger.error("Exception in HostReservationReleaseChecker", t); + } + } + } + + private void checkHostReservations() { + List reservedHosts = _plannerHostReserveDao.listAllReservedHosts(); + + for (PlannerHostReservationVO hostReservation : reservedHosts) { + HostVO host = _hostDao.findById(hostReservation.getHostId()); + if (host != null && host.getManagementServerId() != null && host.getManagementServerId() == _nodeId) { + checkHostReservationRelease(hostReservation.getHostId()); + } + } + } @Override @@ -610,14 +684,45 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy _agentMgr.registerForHostEvents(this, true, false, true); _messageBus.subscribe("VM_ReservedCapacity_Free", new MessageSubscriber() { @Override - public void onPublishMessage(String senderAddress, String subject, Object vm) { - checkHostReservationRelease((VMInstanceVO) vm); + public void onPublishMessage(String senderAddress, String subject, Object obj) { + VMInstanceVO vm = ((VMInstanceVO) obj); + s_logger.debug("MessageBus message: host reserved capacity released for VM: " + vm.getLastHostId() + + ", checking if host reservation can be released for host:" + vm.getLastHostId()); + Long hostId = vm.getLastHostId(); + checkHostReservationRelease(hostId); } }); + _vmCapacityReleaseInterval = NumbersUtil.parseInt(_configDao.getValue(Config.CapacitySkipcountingHours.key()), + 3600); + + String hostReservationReleasePeriod = _configDao.getValue(Config.HostReservationReleasePeriod.key()); + if (hostReservationReleasePeriod != null) { + _hostReservationReleasePeriod = Long.parseLong(hostReservationReleasePeriod); + if (_hostReservationReleasePeriod <= 0) + _hostReservationReleasePeriod = Long.parseLong(Config.HostReservationReleasePeriod.getDefaultValue()); + } + + _timer = new Timer("HostReservationReleaseChecker"); + + _nodeId = ManagementServerNode.getManagementServerId(); + return super.configure(name, params); } + @Override + public boolean start() { + _timer.schedule(new HostReservationReleaseChecker(), INITIAL_RESERVATION_RELEASE_CHECKER_DELAY, + _hostReservationReleasePeriod); + return true; + } + + @Override + public boolean stop() { + _timer.cancel(); + return true; + } + // /refactoring planner methods private DeployDestination checkClustersforDestination(List clusterList, VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid, http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0e792eb9/server/src/com/cloud/deploy/FirstFitPlanner.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/deploy/FirstFitPlanner.java b/server/src/com/cloud/deploy/FirstFitPlanner.java index ad1b9b3..f4dbca5 100755 --- a/server/src/com/cloud/deploy/FirstFitPlanner.java +++ b/server/src/com/cloud/deploy/FirstFitPlanner.java @@ -106,6 +106,7 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentClusterPla protected String _allocationAlgorithm = "random"; + protected String _globalDeploymentPlanner = "FirstFitPlanner"; @Override @@ -483,12 +484,16 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentClusterPla @Override public boolean canHandle(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid) { - // check what the ServiceOffering says + // check what the ServiceOffering says. If null, check the global config ServiceOffering offering = vm.getServiceOffering(); if (offering != null && offering.getDeploymentPlanner() != null) { if (offering.getDeploymentPlanner().equals(this.getName())) { return true; } + } else { + if (_globalDeploymentPlanner != null && _globalDeploymentPlanner.equals(this._name)) { + return true; + } } return false; } @@ -497,6 +502,7 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentClusterPla public boolean configure(String name, Map params) throws ConfigurationException { super.configure(name, params); _allocationAlgorithm = _configDao.getValue(Config.VmAllocationAlgorithm.key()); + _globalDeploymentPlanner = _configDao.getValue(Config.VmDeploymentPlanner.key()); return true; } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0e792eb9/server/src/com/cloud/deploy/dao/PlannerHostReservationDao.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/deploy/dao/PlannerHostReservationDao.java b/server/src/com/cloud/deploy/dao/PlannerHostReservationDao.java index 71e235d..69118f1 100644 --- a/server/src/com/cloud/deploy/dao/PlannerHostReservationDao.java +++ b/server/src/com/cloud/deploy/dao/PlannerHostReservationDao.java @@ -16,6 +16,8 @@ // under the License. package com.cloud.deploy.dao; +import java.util.List; + import com.cloud.deploy.PlannerHostReservationVO; import com.cloud.utils.db.GenericDao; @@ -23,4 +25,6 @@ public interface PlannerHostReservationDao extends GenericDao listAllReservedHosts(); + } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0e792eb9/server/src/com/cloud/deploy/dao/PlannerHostReservationDaoImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/deploy/dao/PlannerHostReservationDaoImpl.java b/server/src/com/cloud/deploy/dao/PlannerHostReservationDaoImpl.java index 7b12067..41e0964 100644 --- a/server/src/com/cloud/deploy/dao/PlannerHostReservationDaoImpl.java +++ b/server/src/com/cloud/deploy/dao/PlannerHostReservationDaoImpl.java @@ -16,6 +16,8 @@ // under the License. package com.cloud.deploy.dao; +import java.util.List; + import javax.annotation.PostConstruct; import javax.ejb.Local; import com.cloud.deploy.PlannerHostReservationVO; @@ -28,6 +30,7 @@ public class PlannerHostReservationDaoImpl extends GenericDaoBase _hostIdSearch; + private SearchBuilder _reservedHostSearch; public PlannerHostReservationDaoImpl() { @@ -38,6 +41,10 @@ public class PlannerHostReservationDaoImpl extends GenericDaoBase listAllReservedHosts() { + SearchCriteria sc = _reservedHostSearch.create(); + return listBy(sc); + } + } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0e792eb9/server/src/com/cloud/resource/ResourceManagerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index c9c3f9c..504c6c2 100755 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -79,6 +79,10 @@ import com.cloud.dc.dao.ClusterVSMMapDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.DataCenterIpAddressDao; import com.cloud.dc.dao.HostPodDao; +import com.cloud.deploy.PlannerHostReservationVO; +import com.cloud.deploy.dao.PlannerHostReservationDao; +import com.cloud.event.ActionEvent; +import com.cloud.event.EventTypes; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.DiscoveryException; import com.cloud.exception.InvalidParameterValueException; @@ -206,6 +210,8 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, protected HighAvailabilityManager _haMgr; @Inject protected StorageService _storageSvr; + @Inject + PlannerHostReservationDao _plannerHostReserveDao; protected List _discoverers; public List getDiscoverers() { @@ -2845,4 +2851,41 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, ResourceState.Enabled); return sc.list(); } + + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_HOST_RESERVATION_RELEASE, eventDescription = "releasing host reservation", async = true) + public boolean releaseHostReservation(Long hostId) { + Transaction txn = Transaction.currentTxn(); + try { + txn.start(); + PlannerHostReservationVO reservationEntry = _plannerHostReserveDao.findByHostId(hostId); + if (reservationEntry != null) { + long id = reservationEntry.getId(); + PlannerHostReservationVO hostReservation = _plannerHostReserveDao.lockRow(id, true); + if (hostReservation == null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Host reservation for host: " + hostId + " does not even exist. Release reservartion call is ignored."); + } + txn.rollback(); + return false; + } + hostReservation.setResourceUsage(null); + _plannerHostReserveDao.persist(hostReservation); + txn.commit(); + return true; + } + if (s_logger.isDebugEnabled()) { + s_logger.debug("Host reservation for host: " + hostId + + " does not even exist. Release reservartion call is ignored."); + } + return false; + } catch (CloudRuntimeException e) { + throw e; + } catch (Throwable t) { + s_logger.error("Unable to release host reservation for host: " + hostId, t); + txn.rollback(); + return false; + } + } } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0e792eb9/server/src/com/cloud/server/ManagementServerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 93bb096..3b75a5f 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -2556,6 +2556,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(UpdateVMAffinityGroupCmd.class); cmdList.add(ListAffinityGroupTypesCmd.class); cmdList.add(ListDeploymentPlannersCmd.class); + cmdList.add(ReleaseHostReservationCmd.class); return cmdList; } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0e792eb9/server/src/com/cloud/service/ServiceOfferingVO.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/service/ServiceOfferingVO.java b/server/src/com/cloud/service/ServiceOfferingVO.java index 32e0e32..fd31d30 100755 --- a/server/src/com/cloud/service/ServiceOfferingVO.java +++ b/server/src/com/cloud/service/ServiceOfferingVO.java @@ -69,7 +69,7 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering int sortKey; @Column(name = "deployment_planner") - private String deploymentPlanner = "FirstFitPlanner"; + private String deploymentPlanner = null; protected ServiceOfferingVO() { super(); @@ -87,7 +87,6 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering this.volatileVm = false; this.default_use = defaultUse; this.vm_type = vm_type == null ? null : vm_type.toString().toLowerCase(); - this.deploymentPlanner = "FirstFitPlanner"; } public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitCpuUse, boolean volatileVm, String displayText, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vm_type, Long domainId) { @@ -101,13 +100,11 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering this.limitCpuUse = limitCpuUse; this.volatileVm = volatileVm; this.vm_type = vm_type == null ? null : vm_type.toString().toLowerCase(); - this.deploymentPlanner = "FirstFitPlanner"; } public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitResourceUse, boolean volatileVm, String displayText, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vm_type, Long domainId, String hostTag) { this(name, cpu, ramSize, speed, rateMbps, multicastRateMbps, offerHA, limitResourceUse, volatileVm, displayText, useLocalStorage, recreatable, tags, systemUse, vm_type, domainId); this.hostTag = hostTag; - this.deploymentPlanner = "FirstFitPlanner"; } public ServiceOfferingVO(String name, int cpu, int ramSize, int speed, Integer rateMbps, Integer multicastRateMbps, @@ -116,11 +113,7 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering String hostTag, String deploymentPlanner) { this(name, cpu, ramSize, speed, rateMbps, multicastRateMbps, offerHA, limitResourceUse, volatileVm, displayText, useLocalStorage, recreatable, tags, systemUse, vm_type, domainId, hostTag); - if (deploymentPlanner != null) { - this.deploymentPlanner = deploymentPlanner; - } else { - this.deploymentPlanner = "FirstFitPlanner"; - } + this.deploymentPlanner = deploymentPlanner; } @Override http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0e792eb9/server/src/com/cloud/upgrade/dao/Upgrade410to420.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/upgrade/dao/Upgrade410to420.java b/server/src/com/cloud/upgrade/dao/Upgrade410to420.java index 2f0c2d3..2ee86c0 100644 --- a/server/src/com/cloud/upgrade/dao/Upgrade410to420.java +++ b/server/src/com/cloud/upgrade/dao/Upgrade410to420.java @@ -67,7 +67,7 @@ public class Upgrade410to420 implements DbUpgrade { updatePrimaryStore(conn); addEgressFwRulesForSRXGuestNw(conn); upgradeEIPNetworkOfferings(conn); - updateServiceOfferingDeploymentPlanner(conn); + updateGlobalDeploymentPlanner(conn); } private void updateSystemVmTemplates(Connection conn) { @@ -402,7 +402,7 @@ public class Upgrade410to420 implements DbUpgrade { } } - private void updateServiceOfferingDeploymentPlanner(Connection conn) { + private void updateGlobalDeploymentPlanner(Connection conn) { PreparedStatement pstmt = null; ResultSet rs = null; @@ -429,13 +429,13 @@ public class Upgrade410to420 implements DbUpgrade { plannerName = "UserDispersingPlanner"; } } - // update service offering with the planner name - pstmt = conn.prepareStatement("UPDATE `cloud`.`service_offering` set deployment_planner=?"); + // update vm.deployment.planner global config + pstmt = conn.prepareStatement("UPDATE `cloud`.`configuration` set value=? where name = 'vm.deployment.planner'"); pstmt.setString(1, plannerName); pstmt.executeUpdate(); } } catch (SQLException e) { - throw new CloudRuntimeException("Unable to set deployment_planner for service offerings", e); + throw new CloudRuntimeException("Unable to set vm.deployment.planner global config", e); } finally { try { if (rs != null) { http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0e792eb9/server/src/com/cloud/vm/UserVmManagerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 5e81435..d538884 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -3066,6 +3066,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use // Get serviceOffering for Virtual Machine ServiceOfferingVO offering = _serviceOfferingDao.findByIdIncludingRemoved(vm.getServiceOfferingId()); String plannerName = offering.getDeploymentPlanner(); + if (plannerName == null) { + plannerName = _configDao.getValue(Config.VmDeploymentPlanner.key()); + } String reservationId = vmEntity.reserve(plannerName, plan, new ExcludeList(), new Long(callerUser.getId()).toString()); vmEntity.deploy(reservationId, new Long(callerUser.getId()).toString(), params); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0e792eb9/server/src/com/cloud/vm/dao/VMInstanceDao.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/vm/dao/VMInstanceDao.java b/server/src/com/cloud/vm/dao/VMInstanceDao.java index c604027..830e464 100644 --- a/server/src/com/cloud/vm/dao/VMInstanceDao.java +++ b/server/src/com/cloud/vm/dao/VMInstanceDao.java @@ -38,14 +38,14 @@ public interface VMInstanceDao extends GenericDao, StateDao< * @return list of VMInstanceVO running on that host. */ List listByHostId(long hostId); - + /** * List VMs by zone ID * @param zoneId * @return list of VMInstanceVO in the specified zone */ List listByZoneId(long zoneId); - + /** * List VMs by pod ID * @param podId @@ -59,32 +59,32 @@ public interface VMInstanceDao extends GenericDao, StateDao< * @return list of VMInstanceVO in the specified zone, deployed from the specified template, that are not expunged */ public List listNonExpungedByZoneAndTemplate(long zoneId, long templateId); - + /** * Find vm instance with names like. - * + * * @param name name that fits SQL like. * @return list of VMInstanceVO */ List findVMInstancesLike(String name); - + List findVMInTransition(Date time, State... states); List listByTypes(VirtualMachine.Type... types); - + VMInstanceVO findByIdTypes(long id, VirtualMachine.Type... types); - + VMInstanceVO findVMByInstanceName(String name); void updateProxyId(long id, Long proxyId, Date time); List listByHostIdTypes(long hostid, VirtualMachine.Type... types); - + List listUpByHostIdTypes(long hostid, VirtualMachine.Type... types); List listByZoneIdAndType(long zoneId, VirtualMachine.Type type); List listUpByHostId(Long hostId); List listByLastHostId(Long hostId); - + List listByTypeAndState(VirtualMachine.Type type, State state); List listByAccountId(long accountId); @@ -92,9 +92,9 @@ public interface VMInstanceDao extends GenericDao, StateDao< List listByClusterId(long clusterId); // this does not pull up VMs which are starting List listLHByClusterId(long clusterId); // get all the VMs even starting one on this cluster - + List listVmsMigratingFromHost(Long hostId); - + public Long countRunningByHostId(long hostId); Pair, Map> listClusterIdsInZoneByVmCount(long zoneId, long accountId); @@ -106,7 +106,7 @@ public interface VMInstanceDao extends GenericDao, StateDao< List listHostIdsByVmCount(long dcId, Long podId, Long clusterId, long accountId); Long countRunningByAccount(long accountId); - + List listNonRemovedVmsByTypeAndNetwork(long networkId, VirtualMachine.Type... types); /** @@ -116,4 +116,8 @@ public interface VMInstanceDao extends GenericDao, StateDao< */ List listDistinctHostNames(long networkId, VirtualMachine.Type... types); + List findByHostInStates(Long hostId, State... states); + + List listStartingWithNoHostId(); + } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0e792eb9/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java b/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java index 7198b7c..ffb1a0b 100644 --- a/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java +++ b/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java @@ -5,7 +5,7 @@ // 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, @@ -83,30 +83,32 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem protected GenericSearchBuilder CountRunningByAccount; protected SearchBuilder NetworkTypeSearch; protected GenericSearchBuilder DistinctHostNameSearch; - + protected SearchBuilder HostAndStateSearch; + protected SearchBuilder StartingWithNoHostSearch; + @Inject ResourceTagDao _tagsDao; @Inject NicDao _nicDao; - + protected Attribute _updateTimeAttr; - - private static final String ORDER_CLUSTERS_NUMBER_OF_VMS_FOR_ACCOUNT_PART1 = + + private static final String ORDER_CLUSTERS_NUMBER_OF_VMS_FOR_ACCOUNT_PART1 = "SELECT host.cluster_id, SUM(IF(vm.state='Running' AND vm.account_id = ?, 1, 0)) FROM `cloud`.`host` host LEFT JOIN `cloud`.`vm_instance` vm ON host.id = vm.host_id WHERE "; private static final String ORDER_CLUSTERS_NUMBER_OF_VMS_FOR_ACCOUNT_PART2 = " AND host.type = 'Routing' GROUP BY host.cluster_id ORDER BY 2 ASC "; - + private static final String ORDER_PODS_NUMBER_OF_VMS_FOR_ACCOUNT = "SELECT pod.id, SUM(IF(vm.state='Running' AND vm.account_id = ?, 1, 0)) FROM `cloud`.`host_pod_ref` pod LEFT JOIN `cloud`.`vm_instance` vm ON pod.id = vm.pod_id WHERE pod.data_center_id = ? " + " GROUP BY pod.id ORDER BY 2 ASC "; - + private static final String ORDER_HOSTS_NUMBER_OF_VMS_FOR_ACCOUNT = "SELECT host.id, SUM(IF(vm.state='Running' AND vm.account_id = ?, 1, 0)) FROM `cloud`.`host` host LEFT JOIN `cloud`.`vm_instance` vm ON host.id = vm.host_id WHERE host.data_center_id = ? " + " AND host.pod_id = ? AND host.cluster_id = ? AND host.type = 'Routing' " + " GROUP BY host.id ORDER BY 2 ASC "; @Inject protected HostDao _hostDao; - + public VMInstanceDaoImpl() { } - + @PostConstruct protected void init() { @@ -114,14 +116,14 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem IdStatesSearch.and("id", IdStatesSearch.entity().getId(), Op.EQ); IdStatesSearch.and("states", IdStatesSearch.entity().getState(), Op.IN); IdStatesSearch.done(); - + VMClusterSearch = createSearchBuilder(); SearchBuilder hostSearch = _hostDao.createSearchBuilder(); VMClusterSearch.join("hostSearch", hostSearch, hostSearch.entity().getId(), VMClusterSearch.entity().getHostId(), JoinType.INNER); hostSearch.and("clusterId", hostSearch.entity().getClusterId(), SearchCriteria.Op.EQ); VMClusterSearch.done(); - + LHVMClusterSearch = createSearchBuilder(); SearchBuilder hostSearch1 = _hostDao.createSearchBuilder(); LHVMClusterSearch.join("hostSearch1", hostSearch1, hostSearch1.entity().getId(), LHVMClusterSearch.entity().getLastHostId(), JoinType.INNER); @@ -129,7 +131,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem hostSearch1.and("clusterId", hostSearch1.entity().getClusterId(), SearchCriteria.Op.EQ); LHVMClusterSearch.done(); - + AllFieldsSearch = createSearchBuilder(); AllFieldsSearch.and("host", AllFieldsSearch.entity().getHostId(), Op.EQ); AllFieldsSearch.and("lastHost", AllFieldsSearch.entity().getLastHostId(), Op.EQ); @@ -169,23 +171,23 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem IdTypesSearch.and("id", IdTypesSearch.entity().getId(), Op.EQ); IdTypesSearch.and("types", IdTypesSearch.entity().getType(), Op.IN); IdTypesSearch.done(); - + HostIdTypesSearch = createSearchBuilder(); HostIdTypesSearch.and("hostid", HostIdTypesSearch.entity().getHostId(), Op.EQ); HostIdTypesSearch.and("types", HostIdTypesSearch.entity().getType(), Op.IN); HostIdTypesSearch.done(); - + HostIdUpTypesSearch = createSearchBuilder(); HostIdUpTypesSearch.and("hostid", HostIdUpTypesSearch.entity().getHostId(), Op.EQ); HostIdUpTypesSearch.and("types", HostIdUpTypesSearch.entity().getType(), Op.IN); HostIdUpTypesSearch.and("states", HostIdUpTypesSearch.entity().getState(), Op.NIN); HostIdUpTypesSearch.done(); - + HostUpSearch = createSearchBuilder(); HostUpSearch.and("host", HostUpSearch.entity().getHostId(), Op.EQ); HostUpSearch.and("states", HostUpSearch.entity().getState(), Op.IN); HostUpSearch.done(); - + InstanceNameSearch = createSearchBuilder(); InstanceNameSearch.and("instanceName", InstanceNameSearch.entity().getInstanceName(), Op.EQ); InstanceNameSearch.done(); @@ -194,21 +196,31 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem CountVirtualRoutersByAccount.select(null, Func.COUNT, null); CountVirtualRoutersByAccount.and("account", CountVirtualRoutersByAccount.entity().getAccountId(), SearchCriteria.Op.EQ); CountVirtualRoutersByAccount.and("type", CountVirtualRoutersByAccount.entity().getType(), SearchCriteria.Op.EQ); - CountVirtualRoutersByAccount.and("state", CountVirtualRoutersByAccount.entity().getState(), SearchCriteria.Op.NIN); + CountVirtualRoutersByAccount.and("state", CountVirtualRoutersByAccount.entity().getState(), SearchCriteria.Op.NIN); CountVirtualRoutersByAccount.done(); - + CountRunningByHost = createSearchBuilder(Long.class); CountRunningByHost.select(null, Func.COUNT, null); CountRunningByHost.and("host", CountRunningByHost.entity().getHostId(), SearchCriteria.Op.EQ); CountRunningByHost.and("state", CountRunningByHost.entity().getState(), SearchCriteria.Op.EQ); - CountRunningByHost.done(); + CountRunningByHost.done(); CountRunningByAccount = createSearchBuilder(Long.class); CountRunningByAccount.select(null, Func.COUNT, null); CountRunningByAccount.and("account", CountRunningByAccount.entity().getAccountId(), SearchCriteria.Op.EQ); CountRunningByAccount.and("state", CountRunningByAccount.entity().getState(), SearchCriteria.Op.EQ); - CountRunningByAccount.done(); - + CountRunningByAccount.done(); + + HostAndStateSearch = createSearchBuilder(); + HostAndStateSearch.and("host", HostAndStateSearch.entity().getHostId(), Op.EQ); + HostAndStateSearch.and("states", HostAndStateSearch.entity().getState(), Op.IN); + HostAndStateSearch.done(); + + StartingWithNoHostSearch = createSearchBuilder(); + StartingWithNoHostSearch.and("state", StartingWithNoHostSearch.entity().getState(), Op.EQ); + StartingWithNoHostSearch.and("host", StartingWithNoHostSearch.entity().getHostId(), Op.NULL); + StartingWithNoHostSearch.done(); + _updateTimeAttr = _allAttributes.get("updateTime"); assert _updateTimeAttr != null : "Couldn't get this updateTime attribute"; } @@ -219,7 +231,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem sc.setParameters("account", accountId); return listBy(sc); } - + @Override public List findVMInstancesLike(String name) { SearchCriteria sc = NameLikeSearch.create(); @@ -234,7 +246,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem return listBy(sc); } - + @Override public List listByZoneId(long zoneId) { SearchCriteria sc = AllFieldsSearch.create(); @@ -242,7 +254,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem return listBy(sc); } - + @Override public List listByPodId(long podId) { SearchCriteria sc = AllFieldsSearch.create(); @@ -263,7 +275,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem sc.setJoinParameters("hostSearch1", "clusterId", clusterId); return listBy(sc); } - + @Override public List listByZoneIdAndType(long zoneId, VirtualMachine.Type type) { SearchCriteria sc = AllFieldsSearch.create(); @@ -271,8 +283,8 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem sc.setParameters("type", type.toString()); return listBy(sc); } - - + + @Override public List listNonExpungedByZoneAndTemplate(long zoneId, long templateId) { SearchCriteria sc = ZoneTemplateNonExpungedSearch.create(); @@ -310,7 +322,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem sc.setParameters("states", new Object[] {State.Destroyed, State.Stopped, State.Expunging}); return listBy(sc); } - + @Override public List listUpByHostId(Long hostId) { SearchCriteria sc = HostUpSearch.create(); @@ -318,14 +330,14 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem sc.setParameters("states", new Object[] {State.Starting, State.Running}); return listBy(sc); } - + @Override public List listByTypes(Type... types) { SearchCriteria sc = TypesSearch.create(); sc.setParameters("types", (Object[]) types); return listBy(sc); } - + @Override public List listByTypeAndState(VirtualMachine.Type type, State state) { SearchCriteria sc = AllFieldsSearch.create(); @@ -348,7 +360,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem sc.setParameters("instanceName", name); return findOneBy(sc); } - + @Override public void updateProxyId(long id, Long proxyId, Date time) { VMInstanceVO vo = createForUpdate(); @@ -369,12 +381,12 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem @SuppressWarnings("unchecked") Pair hosts = (Pair)opaque; Long newHostId = hosts.second(); - + VMInstanceVO vmi = (VMInstanceVO)vm; Long oldHostId = vmi.getHostId(); Long oldUpdated = vmi.getUpdated(); Date oldUpdateDate = vmi.getUpdateTime(); - + SearchCriteria sc = StateChangeSearch.create(); sc.setParameters("id", vmi.getId()); sc.setParameters("states", oldState); @@ -383,7 +395,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem vmi.incrUpdated(); UpdateBuilder ub = getUpdateBuilder(vmi); - + ub.set(vmi, "state", newState); ub.set(vmi, "hostId", newHostId); ub.set(vmi, "podIdToDeployIn", vmi.getPodIdToDeployIn()); @@ -393,7 +405,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem if (result == 0 && s_logger.isDebugEnabled()) { VMInstanceVO vo = findByIdIncludingRemoved(vm.getId()); - + if (vo != null) { StringBuilder str = new StringBuilder("Unable to update ").append(vo.toString()); str.append(": DB Data={Host=").append(vo.getHostId()).append("; State=").append(vo.getState().toString()).append("; updated=").append(vo.getUpdated()).append("; time=").append(vo.getUpdateTime()); @@ -407,7 +419,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem } return result > 0; } - + @Override public List listByLastHostId(Long hostId) { SearchCriteria sc = AllFieldsSearch.create(); @@ -415,7 +427,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem sc.setParameters("state", State.Stopped); return listBy(sc); } - + @Override public Long countAllocatedVirtualRoutersForAccount(long accountId) { SearchCriteria sc = CountVirtualRoutersByAccount.create(); @@ -424,7 +436,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem sc.setParameters("state", new Object[] {State.Destroyed, State.Error, State.Expunging}); return customSearch(sc, null).get(0); } - + @Override public List listVmsMigratingFromHost(Long hostId) { SearchCriteria sc = AllFieldsSearch.create(); @@ -432,7 +444,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem sc.setParameters("state", State.Migrating); return listBy(sc); } - + @Override public Long countRunningByHostId(long hostId){ SearchCriteria sc = CountRunningByHost.create(); @@ -455,7 +467,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem pstmt = txn.prepareAutoCloseStatement(sql.toString()); pstmt.setLong(1, accountId); pstmt.setLong(2, zoneId); - + ResultSet rs = pstmt.executeQuery(); while (rs.next()) { Long clusterId = rs.getLong(1); @@ -484,11 +496,11 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem pstmt = txn.prepareAutoCloseStatement(sql.toString()); pstmt.setLong(1, accountId); pstmt.setLong(2, podId); - + ResultSet rs = pstmt.executeQuery(); while (rs.next()) { Long clusterId = rs.getLong(1); - result.add(clusterId); + result.add(clusterId); clusterVmCountMap.put(clusterId, rs.getDouble(2)); } return new Pair, Map>(result, clusterVmCountMap); @@ -511,11 +523,11 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem pstmt = txn.prepareAutoCloseStatement(sql); pstmt.setLong(1, accountId); pstmt.setLong(2, dataCenterId); - + ResultSet rs = pstmt.executeQuery(); while (rs.next()) { Long podId = rs.getLong(1); - result.add(podId); + result.add(podId); podVmCountMap.put(podId, rs.getDouble(2)); } return new Pair, Map>(result, podVmCountMap); @@ -523,7 +535,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem throw new CloudRuntimeException("DB Exception on: " + ORDER_PODS_NUMBER_OF_VMS_FOR_ACCOUNT, e); } catch (Throwable e) { throw new CloudRuntimeException("Caught: " + ORDER_PODS_NUMBER_OF_VMS_FOR_ACCOUNT, e); - } + } } @Override @@ -538,7 +550,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem pstmt.setLong(2, dcId); pstmt.setLong(3, podId); pstmt.setLong(4, clusterId); - + ResultSet rs = pstmt.executeQuery(); while (rs.next()) { result.add(rs.getLong(1)); @@ -548,9 +560,9 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem throw new CloudRuntimeException("DB Exception on: " + ORDER_PODS_NUMBER_OF_VMS_FOR_ACCOUNT, e); } catch (Throwable e) { throw new CloudRuntimeException("Caught: " + ORDER_PODS_NUMBER_OF_VMS_FOR_ACCOUNT, e); - } + } } - + @Override public Long countRunningByAccount(long accountId){ SearchCriteria sc = CountRunningByAccount.create(); @@ -558,18 +570,18 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem sc.setParameters("state", State.Running); return customSearch(sc, null).get(0); } - + @Override public List listNonRemovedVmsByTypeAndNetwork(long networkId, VirtualMachine.Type... types) { if (NetworkTypeSearch == null) { - + SearchBuilder nicSearch = _nicDao.createSearchBuilder(); nicSearch.and("networkId", nicSearch.entity().getNetworkId(), SearchCriteria.Op.EQ); NetworkTypeSearch = createSearchBuilder(); NetworkTypeSearch.and("types", NetworkTypeSearch.entity().getType(), SearchCriteria.Op.IN); NetworkTypeSearch.and("removed", NetworkTypeSearch.entity().getRemoved(), SearchCriteria.Op.NULL); - NetworkTypeSearch.join("nicSearch", nicSearch, NetworkTypeSearch.entity().getId(), + NetworkTypeSearch.join("nicSearch", nicSearch, NetworkTypeSearch.entity().getId(), nicSearch.entity().getInstanceId(), JoinBuilder.JoinType.INNER); NetworkTypeSearch.done(); } @@ -577,27 +589,27 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem SearchCriteria sc = NetworkTypeSearch.create(); if (types != null && types.length != 0) { sc.setParameters("types", (Object[]) types); - } + } sc.setJoinParameters("nicSearch", "networkId", networkId); return listBy(sc); } - - - + + + @Override public List listDistinctHostNames(long networkId, VirtualMachine.Type... types) { if (DistinctHostNameSearch == null) { - + SearchBuilder nicSearch = _nicDao.createSearchBuilder(); nicSearch.and("networkId", nicSearch.entity().getNetworkId(), SearchCriteria.Op.EQ); DistinctHostNameSearch = createSearchBuilder(String.class); DistinctHostNameSearch.selectField(DistinctHostNameSearch.entity().getHostName()); - + DistinctHostNameSearch.and("types", DistinctHostNameSearch.entity().getType(), SearchCriteria.Op.IN); DistinctHostNameSearch.and("removed", DistinctHostNameSearch.entity().getRemoved(), SearchCriteria.Op.NULL); - DistinctHostNameSearch.join("nicSearch", nicSearch, DistinctHostNameSearch.entity().getId(), + DistinctHostNameSearch.join("nicSearch", nicSearch, DistinctHostNameSearch.entity().getId(), nicSearch.entity().getInstanceId(), JoinBuilder.JoinType.INNER); DistinctHostNameSearch.done(); } @@ -605,12 +617,12 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem SearchCriteria sc = DistinctHostNameSearch.create(); if (types != null && types.length != 0) { sc.setParameters("types", (Object[]) types); - } + } sc.setJoinParameters("nicSearch", "networkId", networkId); return customSearch(sc, null); } - + @Override @DB public boolean remove(Long id) { @@ -625,4 +637,19 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem return result; } + @Override + public List findByHostInStates(Long hostId, State... states) { + SearchCriteria sc = HostAndStateSearch.create(); + sc.setParameters("host", hostId); + sc.setParameters("states", (Object[]) states); + return listBy(sc); + } + + @Override + public List listStartingWithNoHostId() { + SearchCriteria sc = StartingWithNoHostSearch.create(); + sc.setParameters("state", State.Starting); + return listBy(sc); + } + } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0e792eb9/server/test/com/cloud/resource/MockResourceManagerImpl.java ---------------------------------------------------------------------- diff --git a/server/test/com/cloud/resource/MockResourceManagerImpl.java b/server/test/com/cloud/resource/MockResourceManagerImpl.java index 5202c31..1fff3a6 100644 --- a/server/test/com/cloud/resource/MockResourceManagerImpl.java +++ b/server/test/com/cloud/resource/MockResourceManagerImpl.java @@ -608,4 +608,10 @@ public class MockResourceManagerImpl extends ManagerBase implements ResourceMana return null; } + @Override + public boolean releaseHostReservation(Long hostId) { + // TODO Auto-generated method stub + return false; + } + } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/0e792eb9/setup/db/db/schema-410to420.sql ---------------------------------------------------------------------- diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index 2e3bcb5..1c82868 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -934,7 +934,10 @@ CREATE TABLE `cloud`.`op_host_planner_reservation` ( CONSTRAINT `fk_planner_reservation__cluster_id` FOREIGN KEY (`cluster_id`) REFERENCES `cloud`.`cluster`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -ALTER TABLE `cloud`.`service_offering` ADD COLUMN `deployment_planner` varchar(255) NOT NULL DEFAULT 'FirstFitPlanner' COMMENT 'Planner heuristics used to deploy a VM of this offering'; +ALTER TABLE `cloud`.`service_offering` ADD COLUMN `deployment_planner` varchar(255) COMMENT 'Planner heuristics used to deploy a VM of this offering; if null global config vm.deployment.planner is used'; + +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'vm.deployment.planner', 'FirstFitPlanner', '[''FirstFitPlanner'', ''UserDispersingPlanner'', ''UserConcentratedPodPlanner'']: DeploymentPlanner heuristic that will be used for VM deployment.'); +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'host.reservation.release.period', '300000', 'The interval in milliseconds between host reservation release checks'); DROP VIEW IF EXISTS `cloud`.`service_offering_view`; CREATE VIEW `cloud`.`service_offering_view` AS