From 89b94bb7547e3f287c534ba5f07b69beff521aec Mon Sep 17 00:00:00 2001 From: Saksham Srivastava Date: Tue, 23 Jul 2013 13:19:23 +0530 Subject: [PATCH] CLOUDSTACK-3382. Alert should be raised if a vm is migrated from dedicated to non-dedicated resource and vice versa. Alerts are generated for VM migration between: 1) Source host is dedicated and destination host is not. 2) Source host is not dedicated and destination host is dedicated. 3) Both hosts are dedicated to different accounts/domains --- .../deploy/dao/PlannerHostReservationDao.java | 2 + .../dao/PlannerHostReservationDaoImpl.java | 15 +- .../src/com/cloud/vm/UserVmManagerImpl.java | 238 ++++++++++++++++-- 3 files changed, 236 insertions(+), 19 deletions(-) diff --git a/server/src/com/cloud/deploy/dao/PlannerHostReservationDao.java b/server/src/com/cloud/deploy/dao/PlannerHostReservationDao.java index 69118f13896..e60254b4866 100644 --- a/server/src/com/cloud/deploy/dao/PlannerHostReservationDao.java +++ b/server/src/com/cloud/deploy/dao/PlannerHostReservationDao.java @@ -27,4 +27,6 @@ public interface PlannerHostReservationDao extends GenericDao listAllReservedHosts(); + List listAllDedicatedHosts(); + } diff --git a/server/src/com/cloud/deploy/dao/PlannerHostReservationDaoImpl.java b/server/src/com/cloud/deploy/dao/PlannerHostReservationDaoImpl.java index 41e09647d7e..06cdab22fad 100644 --- a/server/src/com/cloud/deploy/dao/PlannerHostReservationDaoImpl.java +++ b/server/src/com/cloud/deploy/dao/PlannerHostReservationDaoImpl.java @@ -20,6 +20,8 @@ import java.util.List; import javax.annotation.PostConstruct; import javax.ejb.Local; + +import com.cloud.deploy.DeploymentPlanner.PlannerResourceUsage; import com.cloud.deploy.PlannerHostReservationVO; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; @@ -31,6 +33,7 @@ public class PlannerHostReservationDaoImpl extends GenericDaoBase _hostIdSearch; private SearchBuilder _reservedHostSearch; + private SearchBuilder _dedicatedHostSearch;; public PlannerHostReservationDaoImpl() { @@ -45,6 +48,10 @@ public class PlannerHostReservationDaoImpl extends GenericDaoBase listAllDedicatedHosts() { + SearchCriteria sc = _dedicatedHostSearch.create(); + sc.setParameters("usage", PlannerResourceUsage.Dedicated); + return listBy(sc); + } +} \ No newline at end of file diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index ca1c2328fe2..694ef5bf1c6 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -33,9 +33,6 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.commons.codec.binary.Base64; -import org.apache.log4j.Logger; - import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.affinity.AffinityGroupService; @@ -69,6 +66,8 @@ import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.to.TemplateObjectTO; +import org.apache.commons.codec.binary.Base64; +import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; @@ -107,6 +106,8 @@ import com.cloud.dc.dao.HostPodDao; import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlanner.ExcludeList; +import com.cloud.deploy.PlannerHostReservationVO; +import com.cloud.deploy.dao.PlannerHostReservationDao; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; @@ -178,6 +179,7 @@ import com.cloud.server.ConfigurationServer; import com.cloud.server.Criteria; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.service.dao.ServiceOfferingDetailsDao; import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.GuestOSCategoryVO; import com.cloud.storage.GuestOSVO; @@ -221,6 +223,7 @@ import com.cloud.user.dao.SSHKeyPairDao; import com.cloud.user.dao.UserDao; import com.cloud.user.dao.VmDiskStatisticsDao; import com.cloud.uservm.UserVm; +import com.cloud.utils.DateUtil; import com.cloud.utils.Journal; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; @@ -418,11 +421,16 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir ConfigurationServer _configServer; @Inject AffinityGroupService _affinityGroupService; + @Inject + PlannerHostReservationDao _plannerHostReservationDao; + @Inject + private ServiceOfferingDetailsDao serviceOfferingDetailsDao; protected ScheduledExecutorService _executor = null; protected int _expungeInterval; protected int _expungeDelay; protected boolean _dailyOrHourly = false; + private int capacityReleaseInterval; protected String _name; protected String _instance; @@ -1424,6 +1432,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir String workers = configs.get("expunge.workers"); int wrks = NumbersUtil.parseInt(workers, 10); + capacityReleaseInterval = NumbersUtil.parseInt(_configDao.getValue(Config.CapacitySkipcountingHours.key()), 3600); String time = configs.get("expunge.interval"); _expungeInterval = NumbersUtil.parseInt(time, 86400); @@ -3833,22 +3842,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir + destinationHost.getResourceState()); } - HostVO srcHost = _hostDao.findById(srcHostId); - HostVO destHost = _hostDao.findById(destinationHost.getId()); - //if srcHost is dedicated and destination Host is not - if (checkIfHostIsDedicated(srcHost) && !checkIfHostIsDedicated(destHost)) { - //raise an alert - String msg = "VM is migrated on a non-dedicated host " + destinationHost.getName(); - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_USERVM, vm.getDataCenterId(), vm.getPodIdToDeployIn(), msg, msg); - } - //if srcHost is non dedicated but destination Host is. - if (!checkIfHostIsDedicated(srcHost) && checkIfHostIsDedicated(destHost)) { - //raise an alert - String msg = "VM is migrated on a dedicated host " + destinationHost.getName(); - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_USERVM, vm.getDataCenterId(), vm.getPodIdToDeployIn(), msg, msg); - } + checkHostsDedication(vm, srcHostId, destinationHost.getId()); - // call to core process + // call to core process DataCenterVO dcVO = _dcDao.findById(destinationHost.getDataCenterId()); HostPodVO pod = _podDao.findById(destinationHost.getPodId()); Cluster cluster = _clusterDao.findById(destinationHost.getClusterId()); @@ -3891,6 +3887,210 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir } } + private Long accountOfDedicatedHost(HostVO host) { + long hostId = host.getId(); + DedicatedResourceVO dedicatedHost = _dedicatedDao.findByHostId(hostId); + DedicatedResourceVO dedicatedClusterOfHost = _dedicatedDao.findByClusterId(host.getClusterId()); + DedicatedResourceVO dedicatedPodOfHost = _dedicatedDao.findByPodId(host.getPodId()); + if(dedicatedHost != null) { + return dedicatedHost.getAccountId(); + } + if(dedicatedClusterOfHost != null) { + return dedicatedClusterOfHost.getAccountId(); + } + if(dedicatedPodOfHost != null) { + return dedicatedPodOfHost.getAccountId(); + } + return null; + } + + private Long domainOfDedicatedHost(HostVO host) { + long hostId = host.getId(); + DedicatedResourceVO dedicatedHost = _dedicatedDao.findByHostId(hostId); + DedicatedResourceVO dedicatedClusterOfHost = _dedicatedDao.findByClusterId(host.getClusterId()); + DedicatedResourceVO dedicatedPodOfHost = _dedicatedDao.findByPodId(host.getPodId()); + if(dedicatedHost != null) { + return dedicatedHost.getDomainId(); + } + if(dedicatedClusterOfHost != null) { + return dedicatedClusterOfHost.getDomainId(); + } + if(dedicatedPodOfHost != null) { + return dedicatedPodOfHost.getDomainId(); + } + return null; + } + + public void checkHostsDedication (VMInstanceVO vm, long srcHostId, long destHostId) { + HostVO srcHost = _hostDao.findById(srcHostId); + HostVO destHost = _hostDao.findById(destHostId); + boolean srcExplDedicated = checkIfHostIsDedicated(srcHost); + boolean destExplDedicated = checkIfHostIsDedicated(destHost); + //if srcHost is explicitly dedicated and destination Host is not + if (srcExplDedicated && !destExplDedicated) { + //raise an alert + String msg = "VM is being migrated from a explicitly dedicated host " + srcHost.getName() +" to non-dedicated host " + destHost.getName(); + _alertMgr.sendAlert(AlertManager.ALERT_TYPE_USERVM, vm.getDataCenterId(), vm.getPodIdToDeployIn(), msg, msg); + s_logger.warn(msg); + } + //if srcHost is non dedicated but destination Host is explicitly dedicated + if (!srcExplDedicated && destExplDedicated) { + //raise an alert + String msg = "VM is being migrated from a non dedicated host " + srcHost.getName() + " to a explicitly dedicated host "+ destHost.getName(); + _alertMgr.sendAlert(AlertManager.ALERT_TYPE_USERVM, vm.getDataCenterId(), vm.getPodIdToDeployIn(), msg, msg); + s_logger.warn(msg); + } + + //if hosts are dedicated to different account/domains, raise an alert + if (srcExplDedicated && destExplDedicated) { + if((accountOfDedicatedHost(srcHost) != null) && (accountOfDedicatedHost(srcHost)!= accountOfDedicatedHost(destHost))) { + String msg = "VM is being migrated from host " + srcHost.getName() + " explicitly dedicated to account " + accountOfDedicatedHost(srcHost) + + " to host " + destHost.getName() + " explicitly dedicated to account " + accountOfDedicatedHost(destHost); + _alertMgr.sendAlert(AlertManager.ALERT_TYPE_USERVM, vm.getDataCenterId(), vm.getPodIdToDeployIn(), msg, msg); + s_logger.warn(msg); + } + if((domainOfDedicatedHost(srcHost) != null) && (domainOfDedicatedHost(srcHost)!= domainOfDedicatedHost(destHost))) { + String msg = "VM is being migrated from host " + srcHost.getName() + " explicitly dedicated to domain " + domainOfDedicatedHost(srcHost) + + " to host " + destHost.getName() + " explicitly dedicated to domain " + domainOfDedicatedHost(destHost); + _alertMgr.sendAlert(AlertManager.ALERT_TYPE_USERVM, vm.getDataCenterId(), vm.getPodIdToDeployIn(), msg, msg); + s_logger.warn(msg); + } + } + + // Checks for implicitly dedicated hosts + ServiceOfferingVO deployPlanner = _offeringDao.findById(vm.getServiceOfferingId()); + if(deployPlanner.getDeploymentPlanner() != null && deployPlanner.getDeploymentPlanner().equals("ImplicitDedicationPlanner")) { + //VM is deployed using implicit planner + long accountOfVm = vm.getAccountId(); + String msg = "VM of account " + accountOfVm + " with implicit deployment planner being migrated to host " + destHost.getName(); + //Get all vms on destination host + boolean emptyDestination = false; + List vmsOnDest= getVmsOnHost(destHostId); + if (vmsOnDest == null || vmsOnDest.isEmpty()) { + emptyDestination = true; + } + + if (!emptyDestination) { + //Check if vm is deployed using strict implicit planner + if(!isServiceOfferingUsingPlannerInPreferredMode(vm.getServiceOfferingId())) { + //Check if all vms on destination host are created using strict implicit mode + if(!checkIfAllVmsCreatedInStrictMode(accountOfVm, vmsOnDest)) { + msg = "VM of account " + accountOfVm + " with strict implicit deployment planner being migrated to host " + destHost.getName() + + " not having all vms strict implicitly dedicated to account " + accountOfVm; + } + } else { + //If vm is deployed using preferred implicit planner, check if all vms on destination host must be + //using implicit planner and must belong to same account + for (VMInstanceVO vmsDest : vmsOnDest) { + ServiceOfferingVO destPlanner = _offeringDao.findById(vmsDest.getServiceOfferingId()); + if (!((destPlanner.getDeploymentPlanner() != null && destPlanner.getDeploymentPlanner().equals("ImplicitDedicationPlanner")) && + vmsDest.getAccountId()==accountOfVm)) { + msg = "VM of account " + accountOfVm + " with preffered implicit deployment planner being migrated to host " + destHost.getName() + + " not having all vms implicitly dedicated to account " + accountOfVm; + } + } + } + } + _alertMgr.sendAlert(AlertManager.ALERT_TYPE_USERVM, vm.getDataCenterId(), vm.getPodIdToDeployIn(), msg, msg); + s_logger.warn(msg); + + } else { + //VM is not deployed using implicit planner, check if it migrated between dedicated hosts + List reservedHosts = _plannerHostReservationDao.listAllDedicatedHosts(); + boolean srcImplDedicated = false; + boolean destImplDedicated = false; + String msg = null; + for (PlannerHostReservationVO reservedHost : reservedHosts) { + if(reservedHost.getHostId() == srcHostId) { + srcImplDedicated = true; + } + if(reservedHost.getHostId() == destHostId) { + destImplDedicated = true; + } + } + if(srcImplDedicated) { + if(destImplDedicated){ + msg = "VM is being migrated from implicitly dedicated host " + srcHost.getName() + " to another implicitly dedicated host " + destHost.getName(); + } else { + msg = "VM is being migrated from implicitly dedicated host " + srcHost.getName() + " to shared host " + destHost.getName(); + } + _alertMgr.sendAlert(AlertManager.ALERT_TYPE_USERVM, vm.getDataCenterId(), vm.getPodIdToDeployIn(), msg, msg); + s_logger.warn(msg); + } else { + if (destImplDedicated) { + msg = "VM is being migrated from shared host " + srcHost.getName() + " to implicitly dedicated host " + destHost.getName(); + _alertMgr.sendAlert(AlertManager.ALERT_TYPE_USERVM, vm.getDataCenterId(), vm.getPodIdToDeployIn(), msg, msg); + s_logger.warn(msg); + } + } + } + } + + private List getVmsOnHost(long hostId) { + List vms = _vmInstanceDao.listUpByHostId(hostId); + List vmsByLastHostId = _vmInstanceDao.listByLastHostId(hostId); + if (vmsByLastHostId.size() > 0) { + // check if any VMs are within skip.counting.hours, if yes we have to consider the host. + for (VMInstanceVO stoppedVM : vmsByLastHostId) { + long secondsSinceLastUpdate = (DateUtil.currentGMTTime().getTime() - stoppedVM.getUpdateTime() + .getTime()) / 1000; + if (secondsSinceLastUpdate < capacityReleaseInterval) { + vms.add(stoppedVM); + } + } + } + + return vms; + } + private boolean isServiceOfferingUsingPlannerInPreferredMode(long serviceOfferingId) { + boolean preferred = false; + Map details = serviceOfferingDetailsDao.findDetails(serviceOfferingId); + if (details != null && !details.isEmpty()) { + String preferredAttribute = details.get("ImplicitDedicationMode"); + if (preferredAttribute != null && preferredAttribute.equals("Preferred")) { + preferred = true; + } + } + return preferred; + } + + private boolean checkIfAllVmsCreatedInStrictMode(Long accountId, List allVmsOnHost) { + boolean createdByImplicitStrict = true; + if (allVmsOnHost.isEmpty()) + return false; + for (VMInstanceVO vm : allVmsOnHost) { + if (!isImplicitPlannerUsedByOffering(vm.getServiceOfferingId()) || vm.getAccountId()!= accountId) { + s_logger.info("Host " + vm.getHostId() + " found to be running a vm created by a planner other" + + " than implicit, or running vms of other account"); + createdByImplicitStrict = false; + break; + } else if (isServiceOfferingUsingPlannerInPreferredMode(vm.getServiceOfferingId()) || vm.getAccountId()!= accountId) { + s_logger.info("Host " + vm.getHostId() + " found to be running a vm created by an implicit planner" + + " in preferred mode, or running vms of other account"); + createdByImplicitStrict = false; + break; + } + } + return createdByImplicitStrict; + } + + private boolean isImplicitPlannerUsedByOffering(long offeringId) { + boolean implicitPlannerUsed = false; + ServiceOfferingVO offering = _serviceOfferingDao.findByIdIncludingRemoved(offeringId); + if (offering == null) { + s_logger.error("Couldn't retrieve the offering by the given id : " + offeringId); + } else { + String plannerName = offering.getDeploymentPlanner(); + if (plannerName != null) { + if(plannerName.equals("ImplicitDedicationPlanner")) { + implicitPlannerUsed = true; + } + } + } + + return implicitPlannerUsed; + } + @Override @ActionEvent(eventType = EventTypes.EVENT_VM_MIGRATE, eventDescription = "migrating VM", async = true) public VirtualMachine migrateVirtualMachineWithVolume(Long vmId, Host destinationHost, @@ -4008,6 +4208,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir " migrate to this host"); } + checkHostsDedication(vm, srcHostId, destinationHost.getId()); + VMInstanceVO migratedVm = _itMgr.migrateWithStorage(vm, srcHostId, destinationHost.getId(), volToPoolObjectMap); return migratedVm; }