diff --git a/server/src/main/java/com/cloud/storage/StoragePoolAutomationImpl.java b/server/src/main/java/com/cloud/storage/StoragePoolAutomationImpl.java index 60494dcb05c0..0c8bddfa6500 100644 --- a/server/src/main/java/com/cloud/storage/StoragePoolAutomationImpl.java +++ b/server/src/main/java/com/cloud/storage/StoragePoolAutomationImpl.java @@ -18,19 +18,18 @@ */ package com.cloud.storage; -import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.inject.Inject; -import org.apache.cloudstack.context.CallContext; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.OperationTimedoutException; +import com.cloud.exception.ResourceUnavailableException; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.commons.collections4.CollectionUtils; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import org.springframework.stereotype.Component; @@ -39,32 +38,18 @@ import com.cloud.agent.api.Answer; import com.cloud.agent.api.ModifyStoragePoolCommand; import com.cloud.agent.api.ModifyStoragePoolAnswer; -import com.cloud.alert.AlertManager; import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ResourceManager; import com.cloud.server.ManagementServer; -import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.storage.dao.StoragePoolWorkDao; import com.cloud.storage.dao.VolumeDao; -import com.cloud.user.Account; -import com.cloud.user.User; -import com.cloud.user.dao.UserDao; import com.cloud.utils.Pair; import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.vm.ConsoleProxyVO; -import com.cloud.vm.DomainRouterVO; -import com.cloud.vm.SecondaryStorageVmVO; -import com.cloud.vm.UserVmVO; import com.cloud.vm.VMInstanceVO; -import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.VirtualMachineManager; -import com.cloud.vm.dao.ConsoleProxyDao; -import com.cloud.vm.dao.DomainRouterDao; -import com.cloud.vm.dao.SecondaryStorageVmDao; -import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; @Component @@ -72,30 +57,11 @@ public class StoragePoolAutomationImpl implements StoragePoolAutomation { protected Logger logger = LogManager.getLogger(getClass()); @Inject protected VirtualMachineManager vmMgr; - @Inject - protected SecondaryStorageVmDao _secStrgDao; - @Inject - UserVmDao userVmDao; - @Inject - protected UserDao _userDao; - @Inject - protected DomainRouterDao _domrDao; - @Inject - protected StoragePoolHostDao _storagePoolHostDao; - @Inject - protected AlertManager _alertMgr; - @Inject - protected ConsoleProxyDao _consoleProxyDao; - @Inject protected StoragePoolWorkDao _storagePoolWorkDao; @Inject PrimaryDataStoreDao primaryDataStoreDao; @Inject - StoragePoolDetailsDao storagePoolDetailsDao; - @Inject - DataStoreManager dataStoreMgr; - @Inject protected ResourceManager _resourceMgr; @Inject AgentManager agentMgr; @@ -106,235 +72,281 @@ public class StoragePoolAutomationImpl implements StoragePoolAutomation { @Inject ManagementServer server; @Inject - DataStoreProviderManager providerMgr; - @Inject StorageManager storageManager; @Override public boolean maintain(DataStore store) { - Long userId = CallContext.current().getCallingUserId(); - User user = _userDao.findById(userId); - Account account = CallContext.current().getCallingAccount(); StoragePoolVO pool = primaryDataStoreDao.findById(store.getId()); try { - List spes = null; - // Handling Zone and Cluster wide storage scopes. - // if the storage is ZONE wide then we pass podid and cluster id as null as they will be empty for ZWPS - if (pool.getScope() == ScopeType.ZONE) { - spes = primaryDataStoreDao.listBy(pool.getDataCenterId(), null, null, ScopeType.ZONE); - } else { - spes = primaryDataStoreDao.listBy(pool.getDataCenterId(), pool.getPodId(), pool.getClusterId(), ScopeType.CLUSTER); - } - for (StoragePoolVO sp : spes) { - if (sp.getParent() != pool.getParent() && sp.getId() != pool.getParent()) { // If Datastore cluster is tried to prepare for maintenance then child storage pools are also kept in PrepareForMaintenance mode - if (sp.getStatus() == StoragePoolStatus.PrepareForMaintenance) { - throw new CloudRuntimeException(String.format("Only one storage pool in a cluster can be in PrepareForMaintenance mode, %s is already in PrepareForMaintenance mode ", sp)); - } - } - } - StoragePool storagePool = (StoragePool)store; - - //Handeling the Zone wide and cluster wide primay storage - List hosts = new ArrayList(); - // if the storage scope is ZONE wide, then get all the hosts for which hypervisor ZWSP created to send Modifystoragepoolcommand - //TODO: if it's zone wide, this code will list a lot of hosts in the zone, which may cause performance/OOM issue. - if (pool.getScope().equals(ScopeType.ZONE)) { - if (HypervisorType.Any.equals(pool.getHypervisor())) { - hosts = _resourceMgr.listAllUpAndEnabledHostsInOneZone(pool.getDataCenterId()); - } - else { - hosts = _resourceMgr.listAllUpAndEnabledHostsInOneZoneByHypervisor(pool.getHypervisor(), pool.getDataCenterId()); - } - } else { - hosts = _resourceMgr.listHostsInClusterByStatus(pool.getClusterId(), Status.Up); + getStoragePoolForSpecification(pool); + + List hosts = getHostsForStoragePool(pool); + + if (setNextStateForMaintenance(hosts, pool) == StoragePoolStatus.PrepareForMaintenance) { + removeHeartbeatForHostsFromPool(hosts, pool); + // check to see if other ps exist + // if they do, then we can migrate over the system vms to them + // if they don't, then just stop all vms on this one + List upPools = primaryDataStoreDao.listByStatusInZone(pool.getDataCenterId(), StoragePoolStatus.Up); + boolean restart = !CollectionUtils.isEmpty(upPools); + + // 2. Get a list of all the ROOT volumes within this storage pool + List allVolumes = volumeDao.findByPoolId(pool.getId()); + // 3. Enqueue to the work queue + enqueueMigrationsForVolumes(allVolumes, pool); + // 4. Process the queue + processMigrationWorkloads(pool, restart); } + } catch (Exception e) { + logger.error("Exception in enabling primary storage maintenance:", e); + pool.setStatus(StoragePoolStatus.ErrorInMaintenance); + primaryDataStoreDao.update(pool.getId(), pool); + // TODO decide on what recovery is possible + throw new CloudRuntimeException(e.getMessage()); + } + return true; + } - if (hosts == null || hosts.size() == 0) { - pool.setStatus(StoragePoolStatus.Maintenance); - primaryDataStoreDao.update(pool.getId(), pool); - return true; - } else { - // set the pool state to prepare for maintenance - pool.setStatus(StoragePoolStatus.PrepareForMaintenance); - primaryDataStoreDao.update(pool.getId(), pool); - } - // remove heartbeat - for (HostVO host : hosts) { - ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(false, storagePool); - final Answer answer = agentMgr.easySend(host.getId(), cmd); - if (answer == null || !answer.getResult()) { - if (logger.isDebugEnabled()) { - logger.debug("ModifyStoragePool false failed due to " + ((answer == null) ? "answer null" : answer.getDetails())); - } - } else { - if (logger.isDebugEnabled()) { - logger.debug("ModifyStoragePool false succeeded"); - } - if (pool.getPoolType() == Storage.StoragePoolType.DatastoreCluster) { - logger.debug("Started synchronising datastore cluster storage pool {} with vCenter", pool); - storageManager.syncDatastoreClusterStoragePool(pool.getId(), ((ModifyStoragePoolAnswer) answer).getDatastoreClusterChildren(), host.getId()); - } - } - } - // check to see if other ps exist - // if they do, then we can migrate over the system vms to them - // if they don't, then just stop all vms on this one - List upPools = primaryDataStoreDao.listByStatusInZone(pool.getDataCenterId(), StoragePoolStatus.Up); - boolean restart = true; - if (upPools == null || upPools.size() == 0) { - restart = false; - } + @Override + public boolean cancelMaintain(DataStore store) { + // Change the storage state back to up + StoragePoolVO poolVO = primaryDataStoreDao.findById(store.getId()); + StoragePool pool = (StoragePool)store; - // 2. Get a list of all the ROOT volumes within this storage pool - List allVolumes = volumeDao.findByPoolId(pool.getId()); + List hosts = getHostsForStoragePool(poolVO); - // 3. Enqueue to the work queue - for (VolumeVO volume : allVolumes) { - VMInstanceVO vmInstance = vmDao.findById(volume.getInstanceId()); + if (CollectionUtils.isEmpty(hosts)) { + return true; + } - if (vmInstance == null) { - continue; - } + Pair, Boolean> nfsMountOpts = storageManager.getStoragePoolNFSMountOpts(pool, null); + addHeartbeatToHostsInPool(hosts, pool, nfsMountOpts); - // enqueue sp work - if (vmInstance.getState().equals(State.Running) || vmInstance.getState().equals(State.Starting) || vmInstance.getState().equals(State.Stopping)) { - - try { - StoragePoolWorkVO work = new StoragePoolWorkVO(vmInstance.getId(), pool.getId(), false, false, server.getId()); - _storagePoolWorkDao.persist(work); - } catch (Exception e) { - if (logger.isDebugEnabled()) { - logger.debug("Work record already exists, re-using by re-setting values"); - } - StoragePoolWorkVO work = _storagePoolWorkDao.findByPoolIdAndVmId(pool.getId(), vmInstance.getId()); - work.setStartedAfterMaintenance(false); - work.setStoppedForMaintenance(false); - work.setManagementServerId(server.getId()); - _storagePoolWorkDao.update(work.getId(), work); - } - } + // 2. Get a list of pending work for this queue + List pendingWork = _storagePoolWorkDao.listPendingWorkForCancelMaintenanceByPoolId(poolVO.getId()); + + // 3. work through the queue + cancelMigrationWorkloads(pendingWork); + return false; + } + + private StoragePoolStatus setNextStateForMaintenance(List hosts, StoragePoolVO pool) { + if (CollectionUtils.isEmpty(hosts)) { + pool.setStatus(StoragePoolStatus.Maintenance); + primaryDataStoreDao.update(pool.getId(), pool); + return StoragePoolStatus.Maintenance; + } else { + // set the pool state to prepare for maintenance + pool.setStatus(StoragePoolStatus.PrepareForMaintenance); + primaryDataStoreDao.update(pool.getId(), pool); + return StoragePoolStatus.PrepareForMaintenance; + } + } + + private void processMigrationWorkloads(StoragePoolVO pool, boolean restart) throws ResourceUnavailableException, OperationTimedoutException, InsufficientCapacityException { + List pendingWork = _storagePoolWorkDao.listPendingWorkForPrepareForMaintenanceByPoolId(pool.getId()); + + for (StoragePoolWorkVO work : pendingWork) { + // shut down the running vms + VMInstanceVO vmInstance = vmDao.findById(work.getVmId()); + + if (vmInstance == null) { + continue; } - // 4. Process the queue - List pendingWork = _storagePoolWorkDao.listPendingWorkForPrepareForMaintenanceByPoolId(pool.getId()); + switch (vmInstance.getType()) { + case ConsoleProxy: + case SecondaryStorageVm: + case DomainRouter: + handleVmMigration(restart, work, vmInstance); + break; + case User: + handleStopVmForMigration(work, vmInstance); + break; + } + } + } - for (StoragePoolWorkVO work : pendingWork) { - // shut down the running vms + private void cancelMigrationWorkloads(List pendingWork) { + for (StoragePoolWorkVO work : pendingWork) { + try { VMInstanceVO vmInstance = vmDao.findById(work.getVmId()); if (vmInstance == null) { continue; } - // if the instance is of type consoleproxy, call the console - // proxy - if (vmInstance.getType().equals(VirtualMachine.Type.ConsoleProxy)) { - // call the consoleproxymanager - ConsoleProxyVO consoleProxy = _consoleProxyDao.findById(vmInstance.getId()); - vmMgr.advanceStop(consoleProxy.getUuid(), false); - // update work status - work.setStoppedForMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); + switch (vmInstance.getType()) { + case ConsoleProxy: + case SecondaryStorageVm: + case DomainRouter: + handleVmStart(work, vmInstance); + break; + case User: + handleUserVmStart(work, vmInstance); + break; + } + } catch (Exception e) { + logger.debug("Failed start vm", e); + throw new CloudRuntimeException(e.toString()); + } + } + } - if (restart) { + private void handleStopVmForMigration(StoragePoolWorkVO work, VMInstanceVO vmInstance) throws ResourceUnavailableException, OperationTimedoutException { + vmMgr.advanceStop(vmInstance.getUuid(), false); + // update work status + work.setStoppedForMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } - vmMgr.advanceStart(consoleProxy.getUuid(), null, null); - // update work status - work.setStartedAfterMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - } + private void handleVmMigration(boolean restart, StoragePoolWorkVO work, VMInstanceVO vmInstance) throws ResourceUnavailableException, OperationTimedoutException, InsufficientCapacityException { + handleStopVmForMigration(work, vmInstance); - // if the instance is of type uservm, call the user vm manager - if (vmInstance.getType() == VirtualMachine.Type.User) { - UserVmVO userVm = userVmDao.findById(vmInstance.getId()); - vmMgr.advanceStop(userVm.getUuid(), false); - // update work status - work.setStoppedForMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } + if (restart) { + handleVmStart(work, vmInstance); + } + } + private void handleVmStart(StoragePoolWorkVO work, VMInstanceVO vmInstance) throws InsufficientCapacityException, ResourceUnavailableException, OperationTimedoutException { + vmMgr.advanceStart(vmInstance.getUuid(), null, null); + // update work queue + work.setStartedAfterMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } - // if the instance is of type secondary storage vm, call the - // secondary storage vm manager - if (vmInstance.getType().equals(VirtualMachine.Type.SecondaryStorageVm)) { - SecondaryStorageVmVO secStrgVm = _secStrgDao.findById(vmInstance.getId()); - vmMgr.advanceStop(secStrgVm.getUuid(), false); - // update work status - work.setStoppedForMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); + private void enqueueMigrationsForVolumes(List allVolumes, StoragePoolVO pool) { + for (VolumeVO volume : allVolumes) { + VMInstanceVO vmInstance = vmDao.findById(volume.getInstanceId()); - if (restart) { - vmMgr.advanceStart(secStrgVm.getUuid(), null, null); - // update work status - work.setStartedAfterMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - } + if (vmInstance == null) { + continue; + } - // if the instance is of type domain router vm, call the network - // manager - if (vmInstance.getType().equals(VirtualMachine.Type.DomainRouter)) { - DomainRouterVO domR = _domrDao.findById(vmInstance.getId()); - vmMgr.advanceStop(domR.getUuid(), false); - // update work status - work.setStoppedForMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); + // enqueue sp work + if (vmInstance.getState().equals(State.Running) || vmInstance.getState().equals(State.Starting) || vmInstance.getState().equals(State.Stopping)) { - if (restart) { - vmMgr.advanceStart(domR.getUuid(), null, null); - // update work status - work.setStartedAfterMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); + try { + StoragePoolWorkVO work = new StoragePoolWorkVO(vmInstance.getId(), pool.getId(), false, false, server.getId()); + _storagePoolWorkDao.persist(work); + } catch (Exception e) { + if (logger.isDebugEnabled()) { + logger.debug("Work record already exists, re-using by re-setting values"); } + StoragePoolWorkVO work = _storagePoolWorkDao.findByPoolIdAndVmId(pool.getId(), vmInstance.getId()); + work.setStartedAfterMaintenance(false); + work.setStoppedForMaintenance(false); + work.setManagementServerId(server.getId()); + _storagePoolWorkDao.update(work.getId(), work); } } - } catch (Exception e) { - logger.error("Exception in enabling primary storage maintenance:", e); - pool.setStatus(StoragePoolStatus.ErrorInMaintenance); - primaryDataStoreDao.update(pool.getId(), pool); - throw new CloudRuntimeException(e.getMessage()); } - return true; } - @Override - public boolean cancelMaintain(DataStore store) { - // Change the storage state back to up - Long userId = CallContext.current().getCallingUserId(); - User user = _userDao.findById(userId); - Account account = CallContext.current().getCallingAccount(); - StoragePoolVO poolVO = primaryDataStoreDao.findById(store.getId()); - StoragePool pool = (StoragePool)store; + private void removeHeartbeatForHostsFromPool(List hosts, StoragePool storagePool) { + // remove heartbeat + for (HostVO host : hosts) { + ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(false, storagePool); + final Answer answer = agentMgr.easySend(host.getId(), cmd); + if (answer == null || !answer.getResult()) { + if (logger.isDebugEnabled()) { + logger.debug("ModifyStoragePool false failed due to {}", ((answer == null) ? "answer null" : answer.getDetails())); + } + } else { + reportSucceededModifyStorePool(storagePool, (ModifyStoragePoolAnswer) answer, host, false); + } + } + } - //Handeling the Zone wide and cluster wide primay storage - List hosts = new ArrayList(); - // if the storage scope is ZONE wide, then get all the hosts for which hypervisor ZWSP created to send Modifystoragepoolcommand - if (poolVO.getScope().equals(ScopeType.ZONE)) { + private void reportSucceededModifyStorePool(StoragePool storagePool, ModifyStoragePoolAnswer answer, HostVO host, boolean add) { + if (logger.isDebugEnabled()) { + logger.debug("ModifyStoragePool succeeded for {}", add ? "adding" : "removing"); + } + if (storagePool.getPoolType() == Storage.StoragePoolType.DatastoreCluster) { + logger.debug("Started synchronising datastore cluster storage pool {} with vCenter", storagePool); + storageManager.syncDatastoreClusterStoragePool(storagePool.getId(), answer.getDatastoreClusterChildren(), host.getId()); + } + } + + /** + * Handling the Zone wide and cluster wide primary storage + * if the storage scope is ZONE wide, then get all the hosts for which hypervisor ZoneWideStoragePools created to send ModifyStoragePoolCommand + * TODO: if it's zone wide, this code will list a lot of hosts in the zone, which may cause performance/OOM issue. + * @param pool pool to check for connected hosts + * @return a list of connected hosts + */ + private List getHostsForStoragePool(StoragePoolVO pool) { + List hosts; + if (pool.getScope().equals(ScopeType.ZONE)) { if (HypervisorType.Any.equals(pool.getHypervisor())) { hosts = _resourceMgr.listAllUpAndEnabledHostsInOneZone(pool.getDataCenterId()); } else { - hosts = _resourceMgr.listAllUpAndEnabledHostsInOneZoneByHypervisor(poolVO.getHypervisor(), pool.getDataCenterId()); + hosts = _resourceMgr.listAllUpAndEnabledHostsInOneZoneByHypervisor(pool.getHypervisor(), pool.getDataCenterId()); } } else { hosts = _resourceMgr.listHostsInClusterByStatus(pool.getClusterId(), Status.Up); } + return hosts; + } - if (hosts == null || hosts.size() == 0) { - return true; + /** + * Handling Zone and Cluster wide storage scopes. Depending on the scope of the pool, check for other storage pools in the same scope + * If the storage is ZONE wide then we pass podId and cluster id as null as they will be empty for Zone wide storage + * + * @param pool pool to check for other pools in the same scope + */ + private void getStoragePoolForSpecification(StoragePoolVO pool) { + List storagePools; + if (pool.getScope() == ScopeType.ZONE) { + storagePools = primaryDataStoreDao.listBy(pool.getDataCenterId(), null, null, ScopeType.ZONE); + } else { + storagePools = primaryDataStoreDao.listBy(pool.getDataCenterId(), pool.getPodId(), pool.getClusterId(), ScopeType.CLUSTER); } + checkHierarchyForPreparingForMaintenance(pool, storagePools); + } - Pair, Boolean> nfsMountOpts = storageManager.getStoragePoolNFSMountOpts(pool, null); - // add heartbeat + /** + * If Datastore cluster is tried to prepare for maintenance then child storage pools are also kept in PrepareForMaintenance mode + * @param pool target to put in maintenance + * @param storagePools list of possible peers/parents/children + */ + private static void checkHierarchyForPreparingForMaintenance(StoragePoolVO pool, List storagePools) { + for (StoragePoolVO storagePool : storagePools) { + if (!(storagePool.getParent().equals(pool.getParent()) || !pool.getParent().equals(storagePool.getId())) && + (storagePool.getStatus() == StoragePoolStatus.PrepareForMaintenance)) { + throw new CloudRuntimeException(String.format("Only one storage pool in a cluster can be in PrepareForMaintenance mode, %s is already in PrepareForMaintenance mode ", storagePool)); + } + } + } + + /** + * // check if the vm has a root volume. If not, remove the item from the queue, the vm should be + * // started only when it has at least one root volume attached to it + * // don't allow to start vm that doesn't have a root volume + * @param work work item to handle for this VM + * @param vmInstance VM to start + * @throws InsufficientCapacityException no migration target found + * @throws ResourceUnavailableException a resource required for migration is not in the expected state + * @throws OperationTimedoutException migration operation took too long + */ + private void handleUserVmStart(StoragePoolWorkVO work, VMInstanceVO vmInstance) throws InsufficientCapacityException, ResourceUnavailableException, OperationTimedoutException { + if (volumeDao.findByInstanceAndType(vmInstance.getId(), Volume.Type.ROOT).isEmpty()) { + _storagePoolWorkDao.remove(work.getId()); + } else { + handleVmStart(work, vmInstance); + } + } + + private void addHeartbeatToHostsInPool(List hosts, StoragePool pool, Pair, Boolean> nfsMountOpts) { for (HostVO host : hosts) { ModifyStoragePoolCommand msPoolCmd = new ModifyStoragePoolCommand(true, pool, nfsMountOpts.first()); final Answer answer = agentMgr.easySend(host.getId(), msPoolCmd); if (answer == null || !answer.getResult()) { if (logger.isDebugEnabled()) { - logger.debug("ModifyStoragePool add failed due to " + ((answer == null) ? "answer null" : answer.getDetails())); + logger.debug("ModifyStoragePool add failed due to {}", ((answer == null) ? "answer null" : answer.getDetails())); } if (answer != null && nfsMountOpts.second()) { - logger.error(String.format("Unable to attach storage pool to the host %s due to %s", host, answer.getDetails())); + logger.error("Unable to attach storage pool to the host {} due to {}", host, answer.getDetails()); StringBuilder exceptionSB = new StringBuilder("Unable to attach storage pool to the host ").append(host.getName()); String reason = storageManager.getStoragePoolMountFailureReason(answer.getDetails()); if (reason!= null) { @@ -343,83 +355,8 @@ public boolean cancelMaintain(DataStore store) { throw new CloudRuntimeException(exceptionSB.toString()); } } else { - if (logger.isDebugEnabled()) { - logger.debug("ModifyStoragePool add succeeded"); - } - if (pool.getPoolType() == Storage.StoragePoolType.DatastoreCluster) { - logger.debug("Started synchronising datastore cluster storage pool {} with vCenter", pool); - storageManager.syncDatastoreClusterStoragePool(pool.getId(), ((ModifyStoragePoolAnswer) answer).getDatastoreClusterChildren(), host.getId()); - } + reportSucceededModifyStorePool(pool, (ModifyStoragePoolAnswer) answer, host, true); } } - - // 2. Get a list of pending work for this queue - List pendingWork = _storagePoolWorkDao.listPendingWorkForCancelMaintenanceByPoolId(poolVO.getId()); - - // 3. work through the queue - for (StoragePoolWorkVO work : pendingWork) { - try { - VMInstanceVO vmInstance = vmDao.findById(work.getVmId()); - - if (vmInstance == null) { - continue; - } - - // if the instance is of type consoleproxy, call the console - // proxy - if (vmInstance.getType().equals(VirtualMachine.Type.ConsoleProxy)) { - - ConsoleProxyVO consoleProxy = _consoleProxyDao - .findById(vmInstance.getId()); - vmMgr.advanceStart(consoleProxy.getUuid(), null, null); - // update work queue - work.setStartedAfterMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - - // if the instance is of type ssvm, call the ssvm manager - if (vmInstance.getType().equals( - VirtualMachine.Type.SecondaryStorageVm)) { - SecondaryStorageVmVO ssVm = _secStrgDao.findById(vmInstance - .getId()); - vmMgr.advanceStart(ssVm.getUuid(), null, null); - - // update work queue - work.setStartedAfterMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - - // if the instance is of type domain router vm, call the network - // manager - if (vmInstance.getType().equals(VirtualMachine.Type.DomainRouter)) { - DomainRouterVO domR = _domrDao.findById(vmInstance.getId()); - vmMgr.advanceStart(domR.getUuid(), null, null); - // update work queue - work.setStartedAfterMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - - // if the instance is of type user vm, call the user vm manager - if (vmInstance.getType().equals(VirtualMachine.Type.User)) { - // check if the vm has a root volume. If not, remove the item from the queue, the vm should be - // started only when it has at least one root volume attached to it - // don't allow to start vm that doesn't have a root volume - if (volumeDao.findByInstanceAndType(vmInstance.getId(), Volume.Type.ROOT).isEmpty()) { - _storagePoolWorkDao.remove(work.getId()); - } else { - UserVmVO userVm = userVmDao.findById(vmInstance.getId()); - - vmMgr.advanceStart(userVm.getUuid(), null, null); - work.setStartedAfterMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - } - } catch (Exception e) { - logger.debug("Failed start vm", e); - throw new CloudRuntimeException(e.toString()); - } - } - return false; } - }