mirror of https://github.com/apache/cloudstack.git
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:
parent
661088927d
commit
fa9ca72f36
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -214,6 +214,7 @@ ldapConfig=1
|
|||
ldapRemove=1
|
||||
listCapabilities=15
|
||||
listDeploymentPlanners=1
|
||||
cleanVMReservations=1
|
||||
|
||||
#### pod commands
|
||||
createPod=1
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue