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
This commit is contained in:
Prachi Damle 2013-07-16 00:52:52 -07:00
parent 661088927d
commit fa9ca72f36
12 changed files with 239 additions and 71 deletions

View File

@ -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

View File

@ -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();
}

View File

@ -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");
}
}
}

View File

@ -214,6 +214,7 @@ ldapConfig=1
ldapRemove=1
listCapabilities=15
listDeploymentPlanners=1
cleanVMReservations=1
#### pod commands
createPod=1

View File

@ -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) {

View File

@ -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);
}

View File

@ -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
@ -147,6 +151,13 @@ public class AffinityGroupVMMapDaoImpl extends GenericDaoBase<AffinityGroupVMMap
return listBy(sc);
}
@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();

View File

@ -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());
// 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;
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;
}

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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