You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by pr...@apache.org on 2013/07/16 22:42:13 UTC
[3/4] git commit: updated refs/heads/4.2 to f53a063
CLOUDSTACK-2155: Anti-Affinity -When Vm deployment is done in parallel , anti-affinity rule is not honored.
Changes:
- Locking the group and save reservation mechanism done by DPM
- Added admin operation to cleanup VM reservations
- DPM will also cleanup VM reservations on startup
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/d70076e6
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/d70076e6
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/d70076e6
Branch: refs/heads/4.2
Commit: d70076e6a5486293000535d8b7e4e781b3f12fca
Parents: 9cb91ba
Author: Prachi Damle <pr...@cloud.com>
Authored: Tue Jul 16 00:52:52 2013 -0700
Committer: Prachi Damle <pr...@cloud.com>
Committed: Tue Jul 16 13:41:16 2013 -0700
----------------------------------------------------------------------
api/src/com/cloud/event/EventTypes.java | 4 +-
api/src/com/cloud/server/ManagementService.java | 14 +--
.../admin/resource/CleanVMReservationsCmd.java | 80 ++++++++++++++++
client/tomcatconf/commands.properties.in | 1 +
.../cloud/entity/api/VMEntityManagerImpl.java | 33 ++-----
.../affinity/dao/AffinityGroupVMMapDao.java | 3 +-
.../affinity/dao/AffinityGroupVMMapDaoImpl.java | 17 +++-
.../affinity/HostAntiAffinityProcessor.java | 36 +++----
.../cloud/deploy/DeploymentPlanningManager.java | 4 +-
.../deploy/DeploymentPlanningManagerImpl.java | 98 ++++++++++++++++++--
.../com/cloud/server/ManagementServerImpl.java | 14 +++
.../vm/DeploymentPlanningManagerImplTest.java | 6 ++
12 files changed, 239 insertions(+), 71 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d70076e6/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 ed4ba12..ca764e9 100755
--- a/api/src/com/cloud/event/EventTypes.java
+++ b/api/src/com/cloud/event/EventTypes.java
@@ -424,7 +424,7 @@ public class EventTypes {
public static final String EVENT_AFFINITY_GROUP_ASSIGN = "AG.ASSIGN";
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_INTERNAL_LB_VM_START = "INTERNALLBVM.START";
public static final String EVENT_INTERNAL_LB_VM_STOP = "INTERNALLBVM.STOP";
@@ -442,6 +442,8 @@ public class EventTypes {
public static final String EVENT_DEDICATE_RESOURCE = "DEDICATE.RESOURCE";
public static final String EVENT_DEDICATE_RESOURCE_RELEASE = "DEDICATE.RESOURCE.RELEASE";
+ public static final String EVENT_CLEANUP_VM_RESERVATION = "VM.RESERVATION.CLEANUP";
+
static {
// TODO: need a way to force author adding event types to declare the entity details as well, with out braking
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d70076e6/api/src/com/cloud/server/ManagementService.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/server/ManagementService.java b/api/src/com/cloud/server/ManagementService.java
index e943a8c..7591ab1 100755
--- a/api/src/com/cloud/server/ManagementService.java
+++ b/api/src/com/cloud/server/ManagementService.java
@@ -16,12 +16,9 @@
// under the License.
package com.cloud.server;
-import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.Set;
-
import com.cloud.exception.*;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.command.admin.cluster.ListClustersCmd;
@@ -43,18 +40,12 @@ import org.apache.cloudstack.api.command.user.event.ArchiveEventsCmd;
import org.apache.cloudstack.api.command.user.event.DeleteEventsCmd;
import org.apache.cloudstack.api.command.user.guest.ListGuestOsCategoriesCmd;
import org.apache.cloudstack.api.command.user.guest.ListGuestOsCmd;
-import org.apache.cloudstack.api.command.user.iso.ListIsosCmd;
-import org.apache.cloudstack.api.command.user.iso.UpdateIsoCmd;
import org.apache.cloudstack.api.command.user.ssh.CreateSSHKeyPairCmd;
import org.apache.cloudstack.api.command.user.ssh.DeleteSSHKeyPairCmd;
import org.apache.cloudstack.api.command.user.ssh.ListSSHKeyPairsCmd;
import org.apache.cloudstack.api.command.user.ssh.RegisterSSHKeyPairCmd;
-import org.apache.cloudstack.api.command.user.template.ListTemplatesCmd;
-import org.apache.cloudstack.api.command.user.template.UpdateTemplateCmd;
import org.apache.cloudstack.api.command.user.vm.GetVMPasswordCmd;
import org.apache.cloudstack.api.command.user.vmgroup.UpdateVMGroupCmd;
-import org.apache.cloudstack.api.command.user.volume.ExtractVolumeCmd;
-
import com.cloud.alert.Alert;
import com.cloud.capacity.Capacity;
import com.cloud.configuration.Configuration;
@@ -69,7 +60,6 @@ import com.cloud.org.Cluster;
import com.cloud.storage.GuestOS;
import com.cloud.storage.GuestOsCategory;
import com.cloud.storage.StoragePool;
-import com.cloud.template.VirtualMachineTemplate;
import com.cloud.user.SSHKeyPair;
import com.cloud.utils.Pair;
import com.cloud.utils.Ternary;
@@ -371,6 +361,8 @@ public interface ManagementService {
List<String> listDeploymentPlanners();
VirtualMachine upgradeSystemVM(ScaleSystemVMCmd cmd) throws ResourceUnavailableException, ManagementServerException, VirtualMachineMigrationException, ConcurrentOperationException;
-
+
boolean getExecuteInSequence();
+
+ void cleanupVMReservations();
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d70076e6/api/src/org/apache/cloudstack/api/command/admin/resource/CleanVMReservationsCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/resource/CleanVMReservationsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/resource/CleanVMReservationsCmd.java
new file mode 100644
index 0000000..b0be7b2
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/resource/CleanVMReservationsCmd.java
@@ -0,0 +1,80 @@
+// 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.resource;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.log4j.Logger;
+
+import com.cloud.event.EventTypes;
+import com.cloud.user.Account;
+import com.cloud.user.UserContext;
+
+@APICommand(name = "cleanVMReservations", description = "Cleanups VM reservations in the database.", responseObject = SuccessResponse.class)
+public class CleanVMReservationsCmd extends BaseAsyncCmd {
+ public static final Logger s_logger = Logger.getLogger(CleanVMReservationsCmd.class.getName());
+
+ private static final String s_name = "cleanvmreservationresponse";
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+
+ /////////////////////////////////////////////////////
+ /////////////// 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_CLEANUP_VM_RESERVATION;
+ }
+
+ @Override
+ public String getEventDescription() {
+ return "cleaning vm reservations in database";
+ }
+
+ @Override
+ public void execute(){
+ try {
+ _mgr.cleanupVMReservations();
+ SuccessResponse response = new SuccessResponse(getCommandName());
+ this.setResponseObject(response);
+ } catch (Exception ex) {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to clean vm reservations");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d70076e6/client/tomcatconf/commands.properties.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in
index ad70471..d8d176f 100644
--- a/client/tomcatconf/commands.properties.in
+++ b/client/tomcatconf/commands.properties.in
@@ -214,6 +214,7 @@ ldapConfig=1
ldapRemove=1
listCapabilities=15
listDeploymentPlanners=1
+cleanVMReservations=1
#### pod commands
createPod=1
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d70076e6/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java
----------------------------------------------------------------------
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 00aeb71..90c1db5 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
@@ -16,7 +16,6 @@
// under the License.
package org.apache.cloudstack.engine.cloud.entity.api;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@@ -30,6 +29,7 @@ import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMEntityDao;
import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMReservationDao;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.dc.DataCenter;
@@ -46,12 +46,10 @@ import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InsufficientServerCapacityException;
import com.cloud.exception.OperationTimedoutException;
import com.cloud.exception.ResourceUnavailableException;
-import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.network.dao.NetworkDao;
import com.cloud.org.Cluster;
import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.storage.StoragePool;
-import com.cloud.storage.Volume;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.storage.dao.VMTemplateDao;
@@ -69,6 +67,8 @@ import com.cloud.vm.dao.VMInstanceDao;
@Component
public class VMEntityManagerImpl implements VMEntityManager {
+ private static final Logger s_logger = Logger.getLogger(VMEntityManagerImpl.class);
+
@Inject
protected VMInstanceDao _vmDao;
@Inject
@@ -190,28 +190,15 @@ public class VMEntityManagerImpl implements VMEntityManager {
}
if (dest != null) {
- if (_dpMgr.finalizeReservation(dest, vmProfile, plan, exclude)) {
- // save destination with VMEntityVO
- VMReservationVO vmReservation = new VMReservationVO(vm.getId(), dest.getDataCenter().getId(), dest
- .getPod().getId(), dest.getCluster().getId(), dest.getHost().getId());
- Map<Long, Long> volumeReservationMap = new HashMap<Long, Long>();
-
- if (vm.getHypervisorType() != HypervisorType.BareMetal) {
- for (Volume vo : dest.getStorageForDisks().keySet()) {
- volumeReservationMap.put(vo.getId(), dest.getStorageForDisks().get(vo).getId());
- }
- vmReservation.setVolumeReservation(volumeReservationMap);
- }
-
- vmEntityVO.setVmReservation(vmReservation);
- _vmEntityDao.persist(vmEntityVO);
-
- return vmReservation.getUuid();
+ String reservationId = _dpMgr.finalizeReservation(dest, vmProfile, plan, exclude);
+ if(reservationId != null){
+ return reservationId;
} else {
- try {
- Thread.sleep(10000);
- } catch (final InterruptedException e) {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Cannot finalize the VM reservation for this destination found, retrying");
}
+
+ exclude.addHost(dest.getHost().getId());
continue;
}
} else if (planChangedByReadyVolume) {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d70076e6/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java b/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java
index f2951bc..5e62b17 100644
--- a/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java
+++ b/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDao.java
@@ -23,7 +23,6 @@ import org.apache.cloudstack.affinity.AffinityGroupVMMapVO;
import com.cloud.utils.Pair;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDao;
-import com.cloud.vm.VirtualMachine.State;
public interface AffinityGroupVMMapDao extends GenericDao<AffinityGroupVMMapVO, Long> {
@@ -44,4 +43,6 @@ public interface AffinityGroupVMMapDao extends GenericDao<AffinityGroupVMMapVO,
List<AffinityGroupVMMapVO> findByVmIdType(long instanceId, String type);
void updateMap(Long vmId, List<Long> affinityGroupIds);
+
+ List<Long> listAffinityGroupIdsByVmId(long instanceId);
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d70076e6/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java b/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java
index e03e73c..89dfa5a 100644
--- a/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java
+++ b/engine/schema/src/org/apache/cloudstack/affinity/dao/AffinityGroupVMMapDaoImpl.java
@@ -24,9 +24,6 @@ import javax.inject.Inject;
import org.apache.cloudstack.affinity.AffinityGroupVMMapVO;
import org.apache.cloudstack.affinity.AffinityGroupVO;
-import org.springframework.stereotype.Component;
-
-import com.cloud.host.HostTagVO;
import com.cloud.utils.Pair;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
@@ -46,6 +43,7 @@ public class AffinityGroupVMMapDaoImpl extends GenericDaoBase<AffinityGroupVMMap
private GenericSearchBuilder<AffinityGroupVMMapVO, Long> ListVmIdByAffinityGroup;
private SearchBuilder<AffinityGroupVMMapVO> ListByAffinityGroup;
private SearchBuilder<AffinityGroupVMMapVO> ListByVmIdType;
+ private GenericSearchBuilder<AffinityGroupVMMapVO, Long> ListAffinityGroupIdByVm;
@Inject
protected AffinityGroupDao _affinityGroupDao;
@@ -87,6 +85,12 @@ public class AffinityGroupVMMapDaoImpl extends GenericDaoBase<AffinityGroupVMMap
CountSGForVm.select(null, Func.COUNT, null);
CountSGForVm.and("vmId", CountSGForVm.entity().getInstanceId(), SearchCriteria.Op.EQ);
CountSGForVm.done();
+
+ ListAffinityGroupIdByVm = createSearchBuilder(Long.class);
+ ListAffinityGroupIdByVm.and("instanceId", ListAffinityGroupIdByVm.entity().getInstanceId(),
+ SearchCriteria.Op.EQ);
+ ListAffinityGroupIdByVm.selectField(ListAffinityGroupIdByVm.entity().getAffinityGroupId());
+ ListAffinityGroupIdByVm.done();
}
@Override
@@ -148,6 +152,13 @@ public class AffinityGroupVMMapDaoImpl extends GenericDaoBase<AffinityGroupVMMap
}
@Override
+ public List<Long> listAffinityGroupIdsByVmId(long instanceId) {
+ SearchCriteria<Long> sc = ListAffinityGroupIdByVm.create();
+ sc.setParameters("instanceId", instanceId);
+ return customSearchIncludingRemoved(sc, null);
+ }
+
+ @Override
public void updateMap(Long vmId, List<Long> affinityGroupIds) {
Transaction txn = Transaction.currentTxn();
txn.start();
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d70076e6/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java
----------------------------------------------------------------------
diff --git a/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java b/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java
index e3c27f0..1569c7e 100644
--- a/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java
+++ b/plugins/affinity-group-processors/host-anti-affinity/src/org/apache/cloudstack/affinity/HostAntiAffinityProcessor.java
@@ -117,7 +117,6 @@ public class HostAntiAffinityProcessor extends AffinityProcessorBase implements
return true;
}
- @DB
@Override
public boolean check(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeployDestination plannedDestination)
throws AffinityConflictException {
@@ -132,31 +131,24 @@ public class HostAntiAffinityProcessor extends AffinityProcessorBase implements
List<AffinityGroupVMMapVO> vmGroupMappings = _affinityGroupVMMapDao.findByVmIdType(vm.getId(), getType());
for (AffinityGroupVMMapVO vmGroupMapping : vmGroupMappings) {
- final Transaction txn = Transaction.currentTxn();
- try {
- txn.start();
- // lock the group
- AffinityGroupVO group = _affinityGroupDao.lockRow(vmGroupMapping.getAffinityGroupId(), true);
- // if more than 1 VM's are present in the group then check for
- // conflict due to parallel deployment
- List<Long> groupVMIds = _affinityGroupVMMapDao.listVmIdsByAffinityGroup(vmGroupMapping
- .getAffinityGroupId());
- groupVMIds.remove(vm.getId());
-
- for (Long groupVMId : groupVMIds) {
- VMReservationVO vmReservation = _reservationDao.findByVmId(groupVMId);
- if (vmReservation.getHostId() != null && vmReservation.getHostId().equals(plannedHostId)) {
- return false;
+ // if more than 1 VM's are present in the group then check for
+ // conflict due to parallel deployment
+ List<Long> groupVMIds = _affinityGroupVMMapDao
+ .listVmIdsByAffinityGroup(vmGroupMapping.getAffinityGroupId());
+ groupVMIds.remove(vm.getId());
+
+ for (Long groupVMId : groupVMIds) {
+ VMReservationVO vmReservation = _reservationDao.findByVmId(groupVMId);
+ if (vmReservation != null && vmReservation.getHostId() != null
+ && vmReservation.getHostId().equals(plannedHostId)) {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Planned destination for VM " + vm.getId() + " conflicts with an existing VM "
+ + vmReservation.getVmId() + " reserved on the same host " + plannedHostId);
}
+ return false;
}
-
- return true;
-
- } finally {
- txn.commit();
}
}
-
return true;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d70076e6/server/src/com/cloud/deploy/DeploymentPlanningManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManager.java b/server/src/com/cloud/deploy/DeploymentPlanningManager.java
index 8e8dc58..9458df2 100644
--- a/server/src/com/cloud/deploy/DeploymentPlanningManager.java
+++ b/server/src/com/cloud/deploy/DeploymentPlanningManager.java
@@ -43,7 +43,9 @@ public interface DeploymentPlanningManager extends Manager {
DeployDestination planDeployment(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan,
ExcludeList avoids) throws InsufficientServerCapacityException, AffinityConflictException;
- boolean finalizeReservation(DeployDestination plannedDestination,
+ String finalizeReservation(DeployDestination plannedDestination,
VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, ExcludeList avoids)
throws InsufficientServerCapacityException, AffinityConflictException;
+
+ void cleanupVMReservations();
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d70076e6/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 5d2d7f2..ebf2b0c 100644
--- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java
+++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java
@@ -31,9 +31,12 @@ import javax.naming.ConfigurationException;
import org.apache.cloudstack.affinity.AffinityGroupProcessor;
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;
+import org.apache.cloudstack.engine.cloud.entity.api.db.VMReservationVO;
+import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMReservationDao;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
import org.apache.cloudstack.framework.messagebus.MessageBus;
@@ -94,12 +97,17 @@ import com.cloud.utils.Pair;
import com.cloud.utils.component.Manager;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.db.DB;
+import com.cloud.utils.db.JoinBuilder;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.fsm.StateListener;
import com.cloud.vm.DiskProfile;
import com.cloud.vm.ReservationContext;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachine.Event;
import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.dao.UserVmDao;
@@ -116,7 +124,8 @@ import com.cloud.agent.manager.allocator.HostAllocator;
@Local(value = { DeploymentPlanningManager.class })
-public class DeploymentPlanningManagerImpl extends ManagerBase implements DeploymentPlanningManager, Manager, Listener {
+public class DeploymentPlanningManagerImpl extends ManagerBase implements DeploymentPlanningManager, Manager, Listener,
+ StateListener<State, VirtualMachine.Event, VirtualMachine> {
private static final Logger s_logger = Logger.getLogger(DeploymentPlanningManagerImpl.class);
@Inject
@@ -138,6 +147,8 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy
MessageBus _messageBus;
private Timer _timer = null;
private long _hostReservationReleasePeriod = 60L * 60L * 1000L; // one hour by default
+ @Inject
+ protected VMReservationDao _reservationDao;
private static final long INITIAL_RESERVATION_RELEASE_CHECKER_DELAY = 30L * 1000L; // thirty seconds expressed in milliseconds
protected long _nodeId = -1;
@@ -766,6 +777,7 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy
@Override
public boolean configure(final String name, final Map<String, Object> params) throws ConfigurationException {
_agentMgr.registerForHostEvents(this, true, false, true);
+ VirtualMachine.State.getStateMachine().registerListener(this);
_messageBus.subscribe("VM_ReservedCapacity_Free", new MessageSubscriber() {
@Override
public void onPublishMessage(String senderAddress, String subject, Object obj) {
@@ -798,6 +810,7 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy
public boolean start() {
_timer.schedule(new HostReservationReleaseChecker(), INITIAL_RESERVATION_RELEASE_CHECKER_DELAY,
_hostReservationReleasePeriod);
+ cleanupVMReservations();
return true;
}
@@ -807,6 +820,26 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy
return true;
}
+ @Override
+ public void cleanupVMReservations() {
+ List<VMReservationVO> reservations = _reservationDao.listAll();
+
+ for (VMReservationVO reserv : reservations) {
+ VMInstanceVO vm = _vmInstanceDao.findById(reserv.getVmId());
+ if (vm != null) {
+ if (vm.getState() == State.Starting || (vm.getState() == State.Stopped && vm.getLastHostId() == null)) {
+ continue;
+ } else {
+ // delete reservation
+ _reservationDao.remove(reserv.getId());
+ }
+ } else {
+ // delete reservation
+ _reservationDao.remove(reserv.getId());
+ }
+ }
+ }
+
// /refactoring planner methods
private DeployDestination checkClustersforDestination(List<Long> clusterList,
VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, ExcludeList avoid,
@@ -1182,25 +1215,72 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy
return false;
}
+ @DB
@Override
- public boolean finalizeReservation(DeployDestination plannedDestination,
+ public String finalizeReservation(DeployDestination plannedDestination,
VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, ExcludeList avoids)
throws InsufficientServerCapacityException, AffinityConflictException {
VirtualMachine vm = vmProfile.getVirtualMachine();
long vmGroupCount = _affinityGroupVMMapDao.countAffinityGroupsForVm(vm.getId());
- DataCenter dc = _dcDao.findById(vm.getDataCenterId());
- if (vmGroupCount > 0) {
- // uses affinity groups. For every group check if processor flags
- // that the destination is ok
- for (AffinityGroupProcessor processor : _affinityProcessors) {
- if (!processor.check(vmProfile, plannedDestination)) {
- return false;
+ boolean saveReservation = true;
+ final Transaction txn = Transaction.currentTxn();
+ try {
+ txn.start();
+ if (vmGroupCount > 0) {
+ List<Long> groupIds = _affinityGroupVMMapDao.listAffinityGroupIdsByVmId(vm.getId());
+ SearchCriteria<AffinityGroupVO> criteria = _affinityGroupDao.createSearchCriteria();
+ criteria.addAnd("id", SearchCriteria.Op.IN, groupIds.toArray(new Object[groupIds.size()]));
+ List<AffinityGroupVO> groups = _affinityGroupDao.lockRows(criteria, null, true);
+
+ for (AffinityGroupProcessor processor : _affinityProcessors) {
+ if (!processor.check(vmProfile, plannedDestination)) {
+ saveReservation = false;
+ break;
+ }
}
}
+
+ if (saveReservation) {
+ VMReservationVO vmReservation = new VMReservationVO(vm.getId(), plannedDestination.getDataCenter()
+ .getId(), plannedDestination.getPod().getId(), plannedDestination.getCluster().getId(),
+ plannedDestination.getHost().getId());
+ Map<Long, Long> volumeReservationMap = new HashMap<Long, Long>();
+
+ if (vm.getHypervisorType() != HypervisorType.BareMetal) {
+ for (Volume vo : plannedDestination.getStorageForDisks().keySet()) {
+ volumeReservationMap.put(vo.getId(), plannedDestination.getStorageForDisks().get(vo).getId());
+ }
+ vmReservation.setVolumeReservation(volumeReservationMap);
+ }
+ _reservationDao.persist(vmReservation);
+ return vmReservation.getUuid();
+ }
+ } finally {
+ txn.commit();
}
+ return null;
+ }
+ @Override
+ public boolean preStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo,
+ boolean status, Object opaque) {
+ return true;
+ }
+
+ @Override
+ public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo,
+ boolean status, Object opaque) {
+ if (!status) {
+ return false;
+ }
+ if ((oldState == State.Starting) && (newState != State.Starting)) {
+ // cleanup all VM reservation entries
+ SearchCriteria<VMReservationVO> sc = _reservationDao.createSearchCriteria();
+ sc.addAnd("vmId", SearchCriteria.Op.EQ, vo.getId());
+ _reservationDao.expunge(sc);
+ }
return true;
}
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d70076e6/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 29272dd..f7fc834 100755
--- a/server/src/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/com/cloud/server/ManagementServerImpl.java
@@ -126,6 +126,7 @@ import org.apache.cloudstack.api.command.admin.pod.DeletePodCmd;
import org.apache.cloudstack.api.command.admin.pod.ListPodsByCmd;
import org.apache.cloudstack.api.command.admin.pod.UpdatePodCmd;
import org.apache.cloudstack.api.command.admin.resource.ArchiveAlertsCmd;
+import org.apache.cloudstack.api.command.admin.resource.CleanVMReservationsCmd;
import org.apache.cloudstack.api.command.admin.resource.DeleteAlertsCmd;
import org.apache.cloudstack.api.command.admin.resource.ListAlertsCmd;
import org.apache.cloudstack.api.command.admin.resource.ListCapacityCmd;
@@ -442,6 +443,7 @@ import com.cloud.dc.dao.VlanDao;
import com.cloud.deploy.DataCenterDeployment;
import com.cloud.deploy.DeploymentPlanner;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
+import com.cloud.deploy.DeploymentPlanningManager;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.event.ActionEvent;
@@ -682,6 +684,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
@Inject
AccountService _accountService;
+ @Inject
+ DeploymentPlanningManager _dpMgr;
+
private final ScheduledExecutorService _eventExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("EventChecker"));
private final ScheduledExecutorService _alertExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("AlertChecker"));
@Inject private KeystoreManager _ksMgr;
@@ -2807,6 +2812,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
cmdList.add(ListNetworkACLListsCmd.class);
cmdList.add(ReplaceNetworkACLListCmd.class);
cmdList.add(UpdateNetworkACLItemCmd.class);
+ cmdList.add(CleanVMReservationsCmd.class);
return cmdList;
}
@@ -3787,4 +3793,12 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
return plannersAvailable;
}
+ @Override
+ public void cleanupVMReservations() {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Processing cleanupVMReservations");
+ }
+
+ _dpMgr.cleanupVMReservations();
+ }
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d70076e6/server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java b/server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java
index 442c2be..10e23d7 100644
--- a/server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java
+++ b/server/test/com/cloud/vm/DeploymentPlanningManagerImplTest.java
@@ -54,6 +54,7 @@ import com.cloud.deploy.dao.PlannerHostReservationDao;
import org.apache.cloudstack.affinity.AffinityGroupProcessor;
import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
+import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMReservationDao;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.framework.messagebus.MessageBus;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
@@ -356,6 +357,11 @@ public class DeploymentPlanningManagerImplTest {
return Mockito.mock(DataCenterDao.class);
}
+ @Bean
+ public VMReservationDao reservationDao() {
+ return Mockito.mock(VMReservationDao.class);
+ }
+
public static class Library implements TypeFilter {
@Override