diff --git a/server/pom.xml b/server/pom.xml index 8b64335d50f..10d80e301b4 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -93,6 +93,11 @@ cloud-api ${project.version} + + org.apache.cloudstack + cloud-framework-ipc + ${project.version} + org.apache.cloudstack cloud-framework-events diff --git a/server/src/com/cloud/capacity/CapacityManagerImpl.java b/server/src/com/cloud/capacity/CapacityManagerImpl.java index 089307fc44c..9a1e97234fd 100755 --- a/server/src/com/cloud/capacity/CapacityManagerImpl.java +++ b/server/src/com/cloud/capacity/CapacityManagerImpl.java @@ -27,6 +27,8 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.framework.messagebus.MessageBus; +import org.apache.cloudstack.framework.messagebus.PublishScope; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.DataCenter; @@ -104,9 +106,9 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, HostDao _hostDao; @Inject VMInstanceDao _vmDao; - @Inject + @Inject VolumeDao _volumeDao; - @Inject + @Inject VMTemplatePoolDao _templatePoolDao; @Inject AgentManager _agentManager; @@ -115,16 +117,16 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, @Inject StorageManager _storageMgr; @Inject - SwiftManager _swiftMgr; + SwiftManager _swiftMgr; @Inject - ConfigurationManager _configMgr; + ConfigurationManager _configMgr; @Inject HypervisorCapabilitiesDao _hypervisorCapabilitiesDao; @Inject protected VMSnapshotDao _vmSnapshotDao; @Inject protected UserVmDao _userVMDao; - + @Inject ClusterDetailsDao _clusterDetailsDao; @Inject @@ -135,6 +137,9 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, long _extraBytesPerVolume = 0; private float _storageOverProvisioningFactor = 1.0f; + @Inject + MessageBus _messageBus; + @Override public boolean configure(String name, Map params) throws ConfigurationException { _vmCapacityReleaseInterval = NumbersUtil.parseInt(_configDao.getValue(Config.CapacitySkipcountingHours.key()), 3600); @@ -398,10 +403,10 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, failureReason = "Host does not have enough reserved CPU available"; } } else { - + long reservedCpuValueToUse = reservedCpu; long reservedMemValueToUse = reservedMem; - + if(!considerReservedCapacity){ if (s_logger.isDebugEnabled()) { s_logger.debug("considerReservedCapacity is" + considerReservedCapacity + " , not considering reserved capacity for calculating free capacity"); @@ -458,7 +463,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, return hasCapacity; } - + private long getVMSnapshotAllocatedCapacity(StoragePoolVO pool){ List volumes = _volumeDao.findByPoolId(pool.getId()); long totalSize = 0; @@ -486,39 +491,39 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, } return totalSize; } - + @Override public long getAllocatedPoolCapacity(StoragePoolVO pool, VMTemplateVO templateForVmCreation){ - + // Get size for all the volumes Pair sizes = _volumeDao.getCountAndTotalByPool(pool.getId()); long totalAllocatedSize = sizes.second() + sizes.first() * _extraBytesPerVolume; - - // Get size for VM Snapshots + + // Get size for VM Snapshots totalAllocatedSize = totalAllocatedSize + getVMSnapshotAllocatedCapacity(pool); // Iterate through all templates on this storage pool boolean tmpinstalled = false; List templatePoolVOs; templatePoolVOs = _templatePoolDao.listByPoolId(pool.getId()); - - for (VMTemplateStoragePoolVO templatePoolVO : templatePoolVOs) { + + for (VMTemplateStoragePoolVO templatePoolVO : templatePoolVOs) { if ((templateForVmCreation != null) && !tmpinstalled && (templatePoolVO.getTemplateId() == templateForVmCreation.getId())) { tmpinstalled = true; } long templateSize = templatePoolVO.getTemplateSize(); totalAllocatedSize += templateSize + _extraBytesPerVolume; } - + // Add the size for the templateForVmCreation if its not already present /*if ((templateForVmCreation != null) && !tmpinstalled) { - + }*/ - + return totalAllocatedSize; } - - + + @DB @Override public void updateCapacityForHost(HostVO host){ @@ -528,7 +533,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, for (ServiceOfferingVO offering : offerings) { offeringsMap.put(offering.getId(), offering); } - + long usedCpu = 0; long usedMemory = 0; long reservedMemory = 0; @@ -555,6 +560,10 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, ServiceOffering so = offeringsMap.get(vm.getServiceOfferingId()); reservedMemory += so.getRamSize() * 1024L * 1024L; reservedCpu += so.getCpu() * so.getSpeed(); + } else { + // signal 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); } } @@ -574,7 +583,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, + usedCpu); cpuCap.setUsedCapacity(usedCpu); } - + if (memCap.getUsedCapacity() == usedMemory && memCap.getReservedCapacity() == reservedMemory) { s_logger.debug("No need to calibrate memory capacity, host:" + host.getId() + " usedMem: " + memCap.getUsedCapacity() + " reservedMem: " + memCap.getReservedCapacity()); @@ -591,7 +600,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, + " new usedMem: " + usedMemory); memCap.setUsedCapacity(usedMemory); } - + try { _capacityDao.update(cpuCap.getId(), cpuCap); _capacityDao.update(memCap.getId(), memCap); @@ -610,11 +619,11 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, capacity.setReservedCapacity(reservedMemory); capacity.setCapacityState(capacityState); _capacityDao.persist(capacity); - + capacity = new CapacityVO( host.getId(), host.getDataCenterId(), - host.getPodId(), + host.getPodId(), host.getClusterId(), usedCpu, (long)(host.getCpus().longValue() * host.getSpeed().longValue()), @@ -623,11 +632,11 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, capacity.setCapacityState(capacityState); _capacityDao.persist(capacity); txn.commit(); - + } - + } - + @Override public boolean preStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vm, boolean transitionStatus, Object opaque) { return true; @@ -681,7 +690,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, releaseVmCapacity(vm, false, false, oldHostId); } } - + if ((newState == State.Starting || newState == State.Migrating || event == Event.AgentReportMigrated) && vm.getHostId() != null) { boolean fromLastHost = false; if (vm.getLastHostId() == vm.getHostId()) { @@ -815,32 +824,32 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, @Override public void processCancelMaintenaceEventAfter(Long hostId) { - updateCapacityForHost(_hostDao.findById(hostId)); + updateCapacityForHost(_hostDao.findById(hostId)); } @Override public void processCancelMaintenaceEventBefore(Long hostId) { // TODO Auto-generated method stub - + } @Override public void processDeletHostEventAfter(HostVO host) { // TODO Auto-generated method stub - + } @Override public void processDeleteHostEventBefore(HostVO host) { // TODO Auto-generated method stub - + } @Override public void processDiscoverEventAfter( Map> resources) { // TODO Auto-generated method stub - + } @Override @@ -848,11 +857,11 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, Long clusterId, URI uri, String username, String password, List hostTags) { // TODO Auto-generated method stub - + } @Override - public void processPrepareMaintenaceEventAfter(Long hostId) { + public void processPrepareMaintenaceEventAfter(Long hostId) { _capacityDao.removeBy(Capacity.CAPACITY_TYPE_MEMORY, null, null, null, hostId); _capacityDao.removeBy(Capacity.CAPACITY_TYPE_CPU, null, null, null, hostId); } @@ -860,7 +869,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, @Override public void processPrepareMaintenaceEventBefore(Long hostId) { // TODO Auto-generated method stub - + } @Override @@ -871,7 +880,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, Long maxGuestLimit = _hypervisorCapabilitiesDao.getMaxGuestsLimit(hypervisorType, hypervisorVersion); if(vmCount.longValue() >= maxGuestLimit.longValue()){ if (s_logger.isDebugEnabled()) { - s_logger.debug("Host name: " + host.getName() + ", hostId: "+ host.getId() + + s_logger.debug("Host name: " + host.getName() + ", hostId: "+ host.getId() + " already reached max Running VMs(count includes system VMs), limit is: " + maxGuestLimit + ",Running VM counts is: "+vmCount.longValue()); } return true; diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java index 6f673c6a5a6..b05d0653496 100644 --- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -34,6 +34,8 @@ import org.apache.cloudstack.affinity.dao.AffinityGroupDao; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; 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; +import org.apache.cloudstack.framework.messagebus.MessageSubscriber; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; @@ -89,6 +91,7 @@ import com.cloud.utils.db.DB; import com.cloud.utils.db.Transaction; import com.cloud.vm.DiskProfile; import com.cloud.vm.ReservationContext; +import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.dao.UserVmDao; @@ -122,6 +125,9 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy @Inject PlannerHostReservationDao _plannerHostReserveDao; + @Inject + MessageBus _messageBus; + protected List _storagePoolAllocators; public List getStoragePoolAllocators() { return _storagePoolAllocators; @@ -488,6 +494,59 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy return false; } + @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(); + + 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); + } + } + + 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); + } + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Host has no VMs, releasing the planner reservation"); + } + + PlannerHostReservationVO reservationEntry = _plannerHostReserveDao.findByHostId(hostId); + if (reservationEntry != null) { + long id = reservationEntry.getId(); + + final Transaction txn = Transaction.currentTxn(); + + try { + txn.start(); + + final PlannerHostReservationVO lockedEntry = _plannerHostReserveDao.lockRow(id, true); + if (lockedEntry == null) { + s_logger.error("Unable to lock the host entry for reservation, host: " + hostId); + } + // check before updating + if (lockedEntry.getResourceUsage() != null) { + lockedEntry.setResourceUsage(null); + _plannerHostReserveDao.persist(lockedEntry); + } + } finally { + txn.commit(); + } + } + + } + } + @Override public boolean processAnswers(long agentId, long seq, Answer[] answers) { // TODO Auto-generated method stub @@ -549,6 +608,13 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy @Override public boolean configure(final String name, final Map params) throws ConfigurationException { _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); + } + }); + return super.configure(name, params); }