From 5d18c4c5273360c8da90798d0205925870c8f00a Mon Sep 17 00:00:00 2001 From: abhishek Date: Fri, 28 Jan 2011 13:39:58 -0800 Subject: [PATCH] bug 8242: introducing the concept of work queue for storage; introducing storage states as opposed to using host states; using row locks as opposed to db table locks status 8242: resolved fixed --- .../api/response/StoragePoolResponse.java | 7 +- api/src/com/cloud/storage/StoragePool.java | 2 +- .../com/cloud/storage/StoragePoolStatus.java | 10 + core/src/com/cloud/storage/StoragePoolVO.java | 12 +- .../com/cloud/storage/StoragePoolWorkVO.java | 100 ++++ .../DefaultComponentLibrary.java | 2 + .../cloud/server/ManagementServerImpl.java | 9 +- .../com/cloud/storage/StorageManagerImpl.java | 534 +++++++++++------- .../AbstractStoragePoolAllocator.java | 3 +- .../com/cloud/storage/dao/StoragePoolDao.java | 4 +- .../cloud/storage/dao/StoragePoolDaoImpl.java | 3 +- .../cloud/storage/dao/StoragePoolWorkDao.java | 39 ++ .../storage/dao/StoragePoolWorkDaoImpl.java | 134 +++++ .../com/cloud/storage/dao/VolumeDaoImpl.java | 1 + .../src/com/cloud/vm/UserVmManagerImpl.java | 7 +- .../cloud/vm/VirtualMachineManagerImpl.java | 2 +- setup/db/create-schema.sql | 11 + 17 files changed, 662 insertions(+), 218 deletions(-) create mode 100644 api/src/com/cloud/storage/StoragePoolStatus.java create mode 100644 core/src/com/cloud/storage/StoragePoolWorkVO.java create mode 100644 server/src/com/cloud/storage/dao/StoragePoolWorkDao.java create mode 100644 server/src/com/cloud/storage/dao/StoragePoolWorkDaoImpl.java diff --git a/api/src/com/cloud/api/response/StoragePoolResponse.java b/api/src/com/cloud/api/response/StoragePoolResponse.java index 9755c614fff..d0047265b78 100644 --- a/api/src/com/cloud/api/response/StoragePoolResponse.java +++ b/api/src/com/cloud/api/response/StoragePoolResponse.java @@ -22,6 +22,7 @@ import java.util.Date; import com.cloud.api.ApiConstants; import com.cloud.host.Status; import com.cloud.serializer.Param; +import com.cloud.storage.StoragePoolStatus; import com.google.gson.annotations.SerializedName; public class StoragePoolResponse extends BaseResponse { @@ -71,7 +72,7 @@ public class StoragePoolResponse extends BaseResponse { private String tags; @SerializedName(ApiConstants.STATE) @Param(description="the state of the storage pool") - private Status state; + private StoragePoolStatus state; @SerializedName(ApiConstants.JOB_ID) @Param(description="shows the current pending asynchronous job ID. This tag is not returned if no current pending jobs are acting on the storage pool") private Long jobId; @@ -203,11 +204,11 @@ public class StoragePoolResponse extends BaseResponse { this.tags = tags; } - public Status getState() { + public StoragePoolStatus getState() { return state; } - public void setState(Status state) { + public void setState(StoragePoolStatus state) { this.state = state; } diff --git a/api/src/com/cloud/storage/StoragePool.java b/api/src/com/cloud/storage/StoragePool.java index 6341118f4e8..28ce7b51699 100644 --- a/api/src/com/cloud/storage/StoragePool.java +++ b/api/src/com/cloud/storage/StoragePool.java @@ -103,7 +103,7 @@ public interface StoragePool { /** * @return the storage pool status */ - Status getStatus(); + StoragePoolStatus getStatus(); int getPort(); diff --git a/api/src/com/cloud/storage/StoragePoolStatus.java b/api/src/com/cloud/storage/StoragePoolStatus.java new file mode 100644 index 00000000000..5d7d296203c --- /dev/null +++ b/api/src/com/cloud/storage/StoragePoolStatus.java @@ -0,0 +1,10 @@ +package com.cloud.storage; + +public enum StoragePoolStatus { + Up, + PrepareForMaintenance, + ErrorInMaintenance, + CancelMaintenance, + Maintenance, + Removed; +} diff --git a/core/src/com/cloud/storage/StoragePoolVO.java b/core/src/com/cloud/storage/StoragePoolVO.java index a2b9cf3c640..79468971ecf 100644 --- a/core/src/com/cloud/storage/StoragePoolVO.java +++ b/core/src/com/cloud/storage/StoragePoolVO.java @@ -80,7 +80,7 @@ public class StoragePoolVO implements StoragePool { @Column(name="status", updatable=true, nullable=false) @Enumerated(value=EnumType.STRING) - private Status status; + private StoragePoolStatus status; @Override public long getId() { @@ -88,7 +88,7 @@ public class StoragePoolVO implements StoragePool { } @Override - public Status getStatus() { + public StoragePoolStatus getStatus() { return status; } @@ -193,7 +193,7 @@ public class StoragePoolVO implements StoragePool { this.path = hostPath; this.port = port; this.podId = podId; - this.setStatus(Status.Up); + this.setStatus(StoragePoolStatus.Up); } public StoragePoolVO(StoragePoolVO that) { @@ -205,10 +205,10 @@ public class StoragePoolVO implements StoragePool { this.hostAddress = hostAddress; this.port = port; this.path = path; - this.setStatus(Status.Up); + this.setStatus(StoragePoolStatus.Up); } - public void setStatus(Status status) + public void setStatus(StoragePoolStatus status) { this.status = status; } @@ -273,7 +273,7 @@ public class StoragePoolVO implements StoragePool { } public boolean isInMaintenance() { - return status == Status.PrepareForMaintenance || status == Status.Maintenance || status == Status.ErrorInMaintenance || removed != null; + return status == StoragePoolStatus.PrepareForMaintenance || status == StoragePoolStatus.Maintenance || status == StoragePoolStatus.ErrorInMaintenance || removed != null; } @Override diff --git a/core/src/com/cloud/storage/StoragePoolWorkVO.java b/core/src/com/cloud/storage/StoragePoolWorkVO.java new file mode 100644 index 00000000000..d19ffea1177 --- /dev/null +++ b/core/src/com/cloud/storage/StoragePoolWorkVO.java @@ -0,0 +1,100 @@ +package com.cloud.storage; + +import javax.persistence.Column; +import javax.persistence.Entity; + +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name="storage_pool_work") +public class StoragePoolWorkVO { + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getPoolId() { + return poolId; + } + + + public void setPoolId(Long poolId) { + this.poolId = poolId; + } + + + public boolean isStoppedForMaintenance() { + return stoppedForMaintenance; + } + + + public void setStoppedForMaintenance(boolean stoppedForMaintenance) { + this.stoppedForMaintenance = stoppedForMaintenance; + } + + + public boolean isStartedAfterMaintenance() { + return startedAfterMaintenance; + } + + public void setStartedAfterMaintenance(boolean startedAfterMaintenance) { + this.startedAfterMaintenance = startedAfterMaintenance; + } + + public Long getVmId() { + return vmId; + } + + public void setVmId(Long vmId) { + this.vmId = vmId; + } + + public Long getManagementServerId() { + return managementServerId; + } + + public void setManagementServerId(Long managementServerId) { + this.managementServerId = managementServerId; + } + + @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) + @Column(name="id") + private Long id; + + @Column(name="pool_id") + private Long poolId; + + @Column(name="vm_id") + private Long vmId; + + @Column(name="stopped_for_maintenance") + private boolean stoppedForMaintenance; + + @Column(name="started_after_maintenance") + private boolean startedAfterMaintenance; + + @Column(name="mgmt_server_id") + private Long managementServerId; + + + public StoragePoolWorkVO(long vmId, long poolId, boolean stoppedForMaintenance, boolean startedAfterMaintenance, long mgmtServerId) { + super(); + this.vmId = vmId; + this.poolId = poolId; + this.stoppedForMaintenance = stoppedForMaintenance; + this.startedAfterMaintenance = startedAfterMaintenance; + this.managementServerId = mgmtServerId; + } + + public StoragePoolWorkVO() { + + } +} diff --git a/server/src/com/cloud/configuration/DefaultComponentLibrary.java b/server/src/com/cloud/configuration/DefaultComponentLibrary.java index 52e80f41f30..c3b3cd450a7 100644 --- a/server/src/com/cloud/configuration/DefaultComponentLibrary.java +++ b/server/src/com/cloud/configuration/DefaultComponentLibrary.java @@ -106,6 +106,7 @@ import com.cloud.storage.dao.SnapshotPolicyDaoImpl; import com.cloud.storage.dao.SnapshotScheduleDaoImpl; import com.cloud.storage.dao.StoragePoolDaoImpl; import com.cloud.storage.dao.StoragePoolHostDaoImpl; +import com.cloud.storage.dao.StoragePoolWorkDaoImpl; import com.cloud.storage.dao.UploadDaoImpl; import com.cloud.storage.dao.VMTemplateDaoImpl; import com.cloud.storage.dao.VMTemplateHostDaoImpl; @@ -256,6 +257,7 @@ public class DefaultComponentLibrary implements ComponentLibrary { addDao("GreTunnelDao", GreTunnelDaoImpl.class); addDao("OvsTunnelDao", OvsTunnelDaoImpl.class); addDao("OvsTunnelAccountDao", OvsTunnelAccountDaoImpl.class); + addDao("StoragePoolWorkDao", StoragePoolWorkDaoImpl.class); } Map> _managers = new HashMap>(); diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 9233edaa454..1d14d94e009 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -196,6 +196,7 @@ import com.cloud.storage.LaunchPermissionVO; import com.cloud.storage.Storage; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePoolHostVO; +import com.cloud.storage.StoragePoolStatus; import com.cloud.storage.StoragePoolVO; import com.cloud.storage.StorageStats; import com.cloud.storage.Upload; @@ -4156,9 +4157,9 @@ public class ManagementServerImpl implements ManagementServer { @Override public long getPsMaintenanceCount(long podId){ List poolsInTransition = new ArrayList(); - poolsInTransition.addAll(_poolDao.listPoolsByStatus(Status.Maintenance)); - poolsInTransition.addAll(_poolDao.listPoolsByStatus(Status.PrepareForMaintenance)); - poolsInTransition.addAll(_poolDao.listPoolsByStatus(Status.ErrorInMaintenance)); + poolsInTransition.addAll(_poolDao.listPoolsByStatus(StoragePoolStatus.Maintenance)); + poolsInTransition.addAll(_poolDao.listPoolsByStatus(StoragePoolStatus.PrepareForMaintenance)); + poolsInTransition.addAll(_poolDao.listPoolsByStatus(StoragePoolStatus.ErrorInMaintenance)); return poolsInTransition.size(); } @@ -4168,7 +4169,7 @@ public class ManagementServerImpl implements ManagementServer { VolumeVO rootVolume = _volumeDao.findByInstance(instanceId).get(0); if(rootVolume!=null){ - Status poolStatus = _poolDao.findById(rootVolume.getPoolId()).getStatus(); + StoragePoolStatus poolStatus = _poolDao.findById(rootVolume.getPoolId()).getStatus(); if(!poolStatus.equals(Status.Up)) { return false; diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index 992415351ed..1e9013a3d82 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -75,6 +75,8 @@ import com.cloud.async.AsyncInstanceCreateStatus; import com.cloud.async.AsyncJobManager; import com.cloud.capacity.CapacityVO; import com.cloud.capacity.dao.CapacityDao; +import com.cloud.cluster.ClusterManagerListener; +import com.cloud.cluster.ManagementServerHostVO; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.ResourceCount.ResourceType; @@ -115,6 +117,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.NetworkManager; import com.cloud.network.router.VirtualNetworkApplianceManager; import com.cloud.offering.ServiceOffering; +import com.cloud.server.ManagementServer; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.Storage.ImageFormat; @@ -127,6 +130,7 @@ import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.dao.StoragePoolDao; import com.cloud.storage.dao.StoragePoolHostDao; +import com.cloud.storage.dao.StoragePoolWorkDao; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VMTemplateHostDao; import com.cloud.storage.dao.VMTemplatePoolDao; @@ -138,6 +142,7 @@ import com.cloud.storage.snapshot.SnapshotScheduler; import com.cloud.template.TemplateManager; import com.cloud.user.Account; import com.cloud.user.AccountManager; +import com.cloud.user.User; import com.cloud.user.UserContext; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; @@ -157,19 +162,26 @@ import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.ExecutionException; +import com.cloud.vm.ConsoleProxyVO; import com.cloud.vm.DiskProfile; +import com.cloud.vm.DomainRouterVO; +import com.cloud.vm.SecondaryStorageVmVO; import com.cloud.vm.UserVmManager; +import com.cloud.vm.UserVmVO; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineManager; import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.VirtualMachine.Type; 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; @Local(value = { StorageManager.class, StorageService.class }) -public class StorageManagerImpl implements StorageManager, StorageService, Manager { +public class StorageManagerImpl implements StorageManager, StorageService, Manager, ClusterManagerListener { private static final Logger s_logger = Logger.getLogger(StorageManagerImpl.class); protected String _name; @@ -212,6 +224,10 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag @Inject protected ClusterDao _clusterDao; @Inject protected VirtualNetworkApplianceManager _routerMgr; @Inject protected UsageEventDao _usageEventDao; + @Inject protected VirtualMachineManager _vmMgr; + @Inject protected DomainRouterDao _domrDao; + @Inject protected SecondaryStorageVmDao _secStrgDao; + @Inject protected StoragePoolWorkDao _storagePoolWorkDao; @Inject(adapter=StoragePoolAllocator.class) @@ -235,6 +251,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag private int _totalRetries; private int _pauseInterval; private final boolean _shouldBeSnapshotCapable = true; + private long _serverId; public boolean share(VMInstanceVO vm, List vols, HostVO host, boolean cancelPreviousShare) throws StorageUnavailableException { @@ -305,7 +322,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag List pools = _storagePoolDao.listAll(); //if no pools or 1 pool which is in maintenance - if(pools == null || pools.size() == 0 || (pools.size() == 1 && pools.get(0).getStatus().equals(Status.Maintenance) )){ + if(pools == null || pools.size() == 0 || (pools.size() == 1 && pools.get(0).getStatus().equals(StoragePoolStatus.Maintenance) )){ return false; }else{ return true; @@ -867,6 +884,8 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag HostSearch.done(); HostTemplateStatesSearch.done(); + _serverId = ((ManagementServer)ComponentLocator.getComponent(ManagementServer.Name)).getId(); + return true; } @@ -1171,7 +1190,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag pool.setPodId(podId); pool.setName(cmd.getStoragePoolName()); pool.setClusterId(clusterId); - pool.setStatus(Status.Up); + pool.setStatus(StoragePoolStatus.Up); pool = _storagePoolDao.persist(pool, details); if (allHosts.isEmpty()) { return pool; @@ -1297,7 +1316,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag _storagePoolHostDao.deleteStoragePoolHostDetails(host.getHostId(),host.getPoolId()); } sPool.setUuid(null); - sPool.setStatus(Status.Removed); + sPool.setStatus(StoragePoolStatus.Removed); _storagePoolDao.update(id, sPool); _storagePoolDao.remove(id); deleteHostorPoolStats(id); @@ -1905,148 +1924,211 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag } @Override @DB - public synchronized StoragePoolVO preparePrimaryStorageForMaintenance(PreparePrimaryStorageForMaintenanceCmd cmd) throws ServerApiException{ + public StoragePoolVO preparePrimaryStorageForMaintenance(PreparePrimaryStorageForMaintenanceCmd cmd) throws ServerApiException{ Long primaryStorageId = cmd.getId(); Long userId = UserContext.current().getCallerUserId(); + User user = _userDao.findById(userId); + Account account = UserContext.current().getCaller(); boolean restart = true; StoragePoolVO primaryStorage = null; try { - Transaction.currentTxn(); - //1. Get the primary storage record and perform validation check - primaryStorage = _storagePoolDao.acquireInLockTable(primaryStorageId); - - if(primaryStorage == null){ - String msg = "Unable to obtain lock on the storage pool in preparePrimaryStorageForMaintenance()"; - s_logger.error(msg); - throw new ExecutionException(msg); - } - - if (!primaryStorage.getStatus().equals(Status.Up) && !primaryStorage.getStatus().equals(Status.ErrorInMaintenance)) { - throw new InvalidParameterValueException("Primary storage with id " + primaryStorageId + " is not ready for migration, as the status is:" + primaryStorage.getStatus().toString()); - } - //set the pool state to prepare for maintenance - primaryStorage.setStatus(Status.PrepareForMaintenance); - _storagePoolDao.persist(primaryStorage); + Transaction txn = Transaction.currentTxn(); + txn.start(); + //1. Get the primary storage record and perform validation check + primaryStorage = _storagePoolDao.lockRow(primaryStorageId, true); + + if(primaryStorage == null){ + String msg = "Unable to obtain lock on the storage pool record in preparePrimaryStorageForMaintenance()"; + s_logger.error(msg); + throw new ExecutionException(msg); + } + + if (!primaryStorage.getStatus().equals(StoragePoolStatus.Up) && !primaryStorage.getStatus().equals(StoragePoolStatus.ErrorInMaintenance)) { + throw new InvalidParameterValueException("Primary storage with id " + primaryStorageId + " is not ready for migration, as the status is:" + primaryStorage.getStatus().toString()); + } + + //set the pool state to prepare for maintenance + primaryStorage.setStatus(StoragePoolStatus.PrepareForMaintenance); + _storagePoolDao.update(primaryStorageId,primaryStorage); + txn.commit(); + //check to see if other ps exist //if they do, then we can migrate over the system vms to them //if they dont, then just stop all vms on this one - List upPools = _storagePoolDao.listPoolsByStatus(Status.Up); + List upPools = _storagePoolDao.listPoolsByStatus(StoragePoolStatus.Up); if(upPools == null || upPools.size() == 0) { restart = false; } - //2. Get a list of all the volumes within this storage pool + //2. Get a list of all the ROOT volumes within this storage pool List allVolumes = _volsDao.findByPoolId(primaryStorageId); - - //3. Each volume has an instance associated with it, stop the instance if running - for(VolumeVO volume : allVolumes) - { - VMInstanceVO vmInstance = _vmInstanceDao.findById(volume.getInstanceId()); - - if(vmInstance == null) { + + //3. Enqueue to the work queue + for(VolumeVO volume : allVolumes) + { + VMInstanceVO vmInstance = _vmInstanceDao.findById(volume.getInstanceId()); + + if(vmInstance == null) { continue; } - - //shut down the running vms - if(vmInstance.getState().equals(State.Running) || vmInstance.getState().equals(State.Starting) || vmInstance.getState().equals(State.Stopping)) - { - - //if the instance is of type consoleproxy, call the console proxy - if(vmInstance.getType().equals(VirtualMachine.Type.ConsoleProxy)) - { - //make sure it is not restarted again, update config to set flag to false - _configMgr.updateConfiguration(userId, "consoleproxy.restart", "false"); - - //call the consoleproxymanager - if(!_consoleProxyMgr.stopProxy(vmInstance.getId())) - { - String errorMsg = "There was an error stopping the console proxy id: "+vmInstance.getId()+" ,cannot enable storage maintenance"; - s_logger.warn(errorMsg); - setPoolStateToError(primaryStorage); - throw new CloudRuntimeException(errorMsg); - } - else if(restart) - { - //Restore config val for consoleproxy.restart to true - _configMgr.updateConfiguration(userId, "consoleproxy.restart", "true"); - - if(_consoleProxyMgr.startProxy(vmInstance.getId())==null) - { - String errorMsg = "There was an error starting the console proxy id: "+vmInstance.getId()+" on another storage pool, cannot enable primary storage maintenance"; - s_logger.warn(errorMsg); - setPoolStateToError(primaryStorage); - throw new CloudRuntimeException(errorMsg); - } - } - } - - //if the instance is of type uservm, call the user vm manager - if(vmInstance.getType().equals(VirtualMachine.Type.User)) - { - //create a dummy event - if(!_userVmMgr.stopVirtualMachine(userId, vmInstance.getId())) - { - String errorMsg = "There was an error stopping the user vm id: "+vmInstance.getId()+" ,cannot enable storage maintenance"; - s_logger.warn(errorMsg); - setPoolStateToError(primaryStorage); - throw new CloudRuntimeException(errorMsg); - } - } - - //if the instance is of type secondary storage vm, call the secondary storage vm manager - if(vmInstance.getType().equals(VirtualMachine.Type.SecondaryStorageVm)) - { - if(!_secStorageMgr.stopSecStorageVm(vmInstance.getId())) - { - String errorMsg = "There was an error stopping the ssvm id: "+vmInstance.getId()+" ,cannot enable storage maintenance"; - s_logger.warn(errorMsg); - setPoolStateToError(primaryStorage); - throw new CloudRuntimeException(errorMsg); - } - else if(restart) - { - if(_secStorageMgr.startSecStorageVm(vmInstance.getId()) == null) - { - String errorMsg = "There was an error starting the ssvm id: "+vmInstance.getId()+" on another storage pool, cannot enable primary storage maintenance"; - s_logger.warn(errorMsg); - setPoolStateToError(primaryStorage); - throw new CloudRuntimeException(errorMsg); - } - } - } + + //enqueue sp work + if(vmInstance.getState().equals(State.Running) || vmInstance.getState().equals(State.Starting) || vmInstance.getState().equals(State.Stopping)){ - //if the instance is of type domain router vm, call the network manager - if(vmInstance.getType().equals(VirtualMachine.Type.DomainRouter)) - { - if(_routerMgr.stopRouter(vmInstance.getId()) == null) - { - String errorMsg = "There was an error stopping the domain router id: "+vmInstance.getId()+" ,cannot enable primary storage maintenance"; - s_logger.warn(errorMsg); - setPoolStateToError(primaryStorage); - throw new CloudRuntimeException(errorMsg); - } - else if(restart) - { - if(_routerMgr.startRouter(vmInstance.getId()) == null) - { - String errorMsg = "There was an error starting the domain router id: "+vmInstance.getId()+" on another storage pool, cannot enable primary storage maintenance"; - s_logger.warn(errorMsg); - setPoolStateToError(primaryStorage); - throw new CloudRuntimeException(errorMsg); - } - } + try { + StoragePoolWorkVO work = new StoragePoolWorkVO(vmInstance.getId(),primaryStorageId, false, false, _serverId); + _storagePoolWorkDao.persist(work); + } catch (Exception e) { + if(s_logger.isDebugEnabled()) + s_logger.debug("Work record already exists, re-using by re-setting values"); + StoragePoolWorkVO work = _storagePoolWorkDao.findByPoolIdAndVmId(primaryStorageId, vmInstance.getId()); + work.setStartedAfterMaintenance(false); + work.setStoppedForMaintenance(false); + work.setManagementServerId(_serverId); + _storagePoolWorkDao.update(work.getId(), work); + } + } + } + + txn.commit(); + txn.close(); + + //4. Process the queue + List pendingWork = _storagePoolWorkDao.listPendingWorkForPrepareForMaintenanceByPoolId(primaryStorageId); + + for(StoragePoolWorkVO work : pendingWork) + { + //shut down the running vms + VMInstanceVO vmInstance = _vmInstanceDao.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)) + { + //make sure it is not restarted again, update config to set flag to false + if(!restart) { + _configMgr.updateConfiguration(userId, "consoleproxy.restart", "false"); + } + + //call the consoleproxymanager + ConsoleProxyVO consoleProxy = _consoleProxyDao.findById(vmInstance.getId()); + if(!_vmMgr.advanceStop(consoleProxy, true, user, account)) + { + String errorMsg = "There was an error stopping the console proxy id: "+vmInstance.getId()+" ,cannot enable storage maintenance"; + s_logger.warn(errorMsg); + throw new CloudRuntimeException(errorMsg); + } else { + //update work status + work.setStoppedForMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); } - } + + if(restart) + { + //Restore config val for consoleproxy.restart to true + _configMgr.updateConfiguration(userId, "consoleproxy.restart", "true"); + + if(_vmMgr.advanceStart(consoleProxy, null, user, account) == null) + { + String errorMsg = "There was an error starting the console proxy id: "+vmInstance.getId()+" on another storage pool, cannot enable primary storage maintenance"; + s_logger.warn(errorMsg); + throw new CloudRuntimeException(errorMsg); + } else { + //update work status + work.setStartedAfterMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + } + } + + //if the instance is of type uservm, call the user vm manager + if(vmInstance.getType().equals(VirtualMachine.Type.User)) + { + UserVmVO userVm = _userVmDao.findById(vmInstance.getId()); + if(!_vmMgr.advanceStop(userVm, true, user, account)) + { + String errorMsg = "There was an error stopping the user vm id: "+vmInstance.getId()+" ,cannot enable storage maintenance"; + s_logger.warn(errorMsg); + throw new CloudRuntimeException(errorMsg); + } else { + //update work status + work.setStoppedForMaintenance(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()); + if(!_vmMgr.advanceStop(secStrgVm, true, user, account)) + { + String errorMsg = "There was an error stopping the ssvm id: "+vmInstance.getId()+" ,cannot enable storage maintenance"; + s_logger.warn(errorMsg); + throw new CloudRuntimeException(errorMsg); + } else { + //update work status + work.setStoppedForMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + + if(restart) + { + if(_vmMgr.advanceStart(secStrgVm, null, user, account) == null) + { + String errorMsg = "There was an error starting the ssvm id: "+vmInstance.getId()+" on another storage pool, cannot enable primary storage maintenance"; + s_logger.warn(errorMsg); + throw new CloudRuntimeException(errorMsg); + } else { + //update work status + 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()); + if(!_vmMgr.advanceStop(domR, true, user, account)) + { + String errorMsg = "There was an error stopping the domain router id: "+vmInstance.getId()+" ,cannot enable primary storage maintenance"; + s_logger.warn(errorMsg); + throw new CloudRuntimeException(errorMsg); + } else { + //update work status + work.setStoppedForMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + + if(restart) + { + if(_vmMgr.advanceStart(domR, null, user, account) == null) + { + String errorMsg = "There was an error starting the domain router id: "+vmInstance.getId()+" on another storage pool, cannot enable primary storage maintenance"; + s_logger.warn(errorMsg); + throw new CloudRuntimeException(errorMsg); + } else { + //update work status + work.setStartedAfterMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + } + } + } //5. Update the status - primaryStorage.setStatus(Status.Maintenance); - _storagePoolDao.persist(primaryStorage); - return _storagePoolDao.findById(primaryStorageId); + primaryStorage.setStatus(StoragePoolStatus.Maintenance); + _storagePoolDao.update(primaryStorageId,primaryStorage); + return _storagePoolDao.findById(primaryStorageId); } catch (Exception e) { if(e instanceof ExecutionException || e instanceof ResourceUnavailableException){ s_logger.error("Exception in enabling primary storage maintenance:",e); @@ -2068,26 +2150,27 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag setPoolStateToError(primaryStorage); throw new ServerApiException(BaseCmd.INTERNAL_ERROR, e.getMessage()); - }finally{ - _storagePoolDao.releaseFromLockTable(primaryStorage.getId()); } } private void setPoolStateToError(StoragePoolVO primaryStorage) { - primaryStorage.setStatus(Status.ErrorInMaintenance); - _storagePoolDao.persist(primaryStorage); + primaryStorage.setStatus(StoragePoolStatus.ErrorInMaintenance); + _storagePoolDao.update(primaryStorage.getId(),primaryStorage); } @Override @DB - public synchronized StoragePoolVO cancelPrimaryStorageForMaintenance(CancelPrimaryStorageMaintenanceCmd cmd) throws ServerApiException{ + public StoragePoolVO cancelPrimaryStorageForMaintenance(CancelPrimaryStorageMaintenanceCmd cmd) throws ServerApiException{ Long primaryStorageId = cmd.getId(); Long userId = UserContext.current().getCallerUserId(); + User user = _userDao.findById(userId); + Account account = UserContext.current().getCaller(); StoragePoolVO primaryStorage = null; try { - Transaction.currentTxn(); + Transaction txn = Transaction.currentTxn(); + txn.start(); //1. Get the primary storage record and perform validation check - primaryStorage = _storagePoolDao.acquireInLockTable(primaryStorageId); + primaryStorage = _storagePoolDao.lockRow(primaryStorageId, true); if(primaryStorage == null){ String msg = "Unable to obtain lock on the storage pool in cancelPrimaryStorageForMaintenance()"; @@ -2095,82 +2178,111 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag throw new ExecutionException(msg); } - if (primaryStorage.getStatus().equals(Status.Up) || primaryStorage.getStatus().equals(Status.PrepareForMaintenance)) { + if (primaryStorage.getStatus().equals(StoragePoolStatus.Up) || primaryStorage.getStatus().equals(StoragePoolStatus.PrepareForMaintenance)) { throw new StorageUnavailableException("Primary storage with id " + primaryStorageId + " is not ready to complete migration, as the status is:" + primaryStorage.getStatus().toString(), primaryStorageId); } //set state to cancelmaintenance - primaryStorage.setStatus(Status.CancelMaintenance); - _storagePoolDao.persist(primaryStorage); + primaryStorage.setStatus(StoragePoolStatus.CancelMaintenance); + _storagePoolDao.update(primaryStorageId,primaryStorage); + txn.commit(); + txn.close(); - //2. Get a list of all the volumes within this storage pool - List allVolumes = _volsDao.findByPoolId(primaryStorageId); + //2. Get a list of pending work for this queue + List pendingWork = _storagePoolWorkDao.listPendingWorkForCancelMaintenanceByPoolId(primaryStorageId); - //3. If the volume is not removed AND not destroyed, start the vm corresponding to it - for(VolumeVO volume: allVolumes) + //3. work through the queue + for(StoragePoolWorkVO work: pendingWork) { - if((volume.getState() != Volume.State.Destroy) && (volume.getRemoved() == null)) - { - VMInstanceVO vmInstance = _vmInstanceDao.findById(volume.getInstanceId()); - if(vmInstance.getState().equals(State.Stopping) || vmInstance.getState().equals(State.Stopped)) + VMInstanceVO vmInstance = _vmInstanceDao.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()); + if(_vmMgr.advanceStart(consoleProxy, null, user, account) == null) { - //if the instance is of type consoleproxy, call the console proxy - if(vmInstance.getType().equals(VirtualMachine.Type.ConsoleProxy)) - { - - if(_consoleProxyMgr.startProxy(vmInstance.getId()) == null) - { - String msg = "There was an error starting the console proxy id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg); - throw new ExecutionException(msg); - } - } - - //if the instance is of type ssvm, call the ssvm manager - if(vmInstance.getType().equals(VirtualMachine.Type.SecondaryStorageVm)) - { - - if(_secStorageMgr.startSecStorageVm(vmInstance.getId()) == null) - { - String msg = "There was an error starting the ssvm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg); - throw new ExecutionException(msg); - } - } - - //if the instance is of type user vm, call the user vm manager - if(vmInstance.getType().equals(VirtualMachine.Type.User)) - { - - try { - if(_userVmMgr.startUserVm(vmInstance.getId()) == null) - { - String msg = "There was an error starting the user vm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg); - throw new ExecutionException(msg); - } - } catch (StorageUnavailableException e) { - String msg = "There was an error starting the user vm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg,e); - throw new ExecutionException(msg); - } catch (InsufficientCapacityException e) { - String msg = "There was an error starting the user vm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg,e); - throw new ExecutionException(msg); - } catch (ConcurrentOperationException e) { - String msg = "There was an error starting the user vm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg,e); - setPoolStateToError(primaryStorage); - throw new ExecutionException(msg); - } catch (ExecutionException e) { - String msg = "There was an error starting the user vm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg,e); - throw new ExecutionException(msg); - } - } + String msg = "There was an error starting the console proxy id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"; + s_logger.warn(msg); + throw new ExecutionException(msg); + } else { + //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()); + if(_vmMgr.advanceStart(ssVm, null, user, account) == null) + { + String msg = "There was an error starting the ssvm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"; + s_logger.warn(msg); + throw new ExecutionException(msg); + }else { + //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.DomainRouter)) + { + DomainRouterVO domR = _domrDao.findById(vmInstance.getId()); + if(_vmMgr.advanceStart(domR, null, user, account) == null) + { + String msg = "There was an error starting the domR id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"; + s_logger.warn(msg); + throw new ExecutionException(msg); + }else { + //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)) + { + UserVmVO userVm = _userVmDao.findById(vmInstance.getId()); + try { + if(_vmMgr.advanceStart(userVm, null, user, account) == null) + { + + String msg = "There was an error starting the user vm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"; + s_logger.warn(msg); + throw new ExecutionException(msg); + } else { + //update work queue + work.setStartedAfterMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + } catch (StorageUnavailableException e) { + String msg = "There was an error starting the user vm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"; + s_logger.warn(msg,e); + throw new ExecutionException(msg); + } catch (InsufficientCapacityException e) { + String msg = "There was an error starting the user vm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"; + s_logger.warn(msg,e); + throw new ExecutionException(msg); + } catch (ConcurrentOperationException e) { + String msg = "There was an error starting the user vm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"; + s_logger.warn(msg,e); + throw new ExecutionException(msg); + } catch (ExecutionException e) { + String msg = "There was an error starting the user vm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"; + s_logger.warn(msg,e); + throw new ExecutionException(msg); + } + } } //Restore config val for consoleproxy.restart to true @@ -2187,8 +2299,8 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag } //Change the storage state back to up - primaryStorage.setStatus(Status.Up); - _storagePoolDao.persist(primaryStorage); + primaryStorage.setStatus(StoragePoolStatus.Up); + _storagePoolDao.update(primaryStorageId, primaryStorage); return primaryStorage; } catch (Exception e) { @@ -2202,8 +2314,6 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag else{//all other exceptions throw new ServerApiException(BaseCmd.INTERNAL_ERROR, e.getMessage()); } - }finally{ - _storagePoolDao.releaseFromLockTable(primaryStorage.getId()); } } @@ -2667,5 +2777,33 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag } } + @Override + public void onManagementNodeJoined(List nodeList, long selfNodeId) { + // TODO Auto-generated method stub + + } + + @Override + public void onManagementNodeLeft(List nodeList, long selfNodeId) { + for (ManagementServerHostVO vo : nodeList) { + if(vo.getMsid() == _serverId) { + s_logger.info("Cleaning up storage maintenance jobs associated with Management server" + vo.getMsid()); + List poolIds = _storagePoolWorkDao.searchForPoolIdsForPendingWorkJobs(vo.getMsid()); + if(poolIds.size() > 0) { + for(Long poolId : poolIds) { + StoragePoolVO pool = _storagePoolDao.findById(poolId); + //check if pool is in an inconsistent state + if(pool != null && (pool.getStatus().equals(StoragePoolStatus.ErrorInMaintenance) || pool.getStatus().equals(StoragePoolStatus.PrepareForMaintenance) || pool.getStatus().equals(StoragePoolStatus.CancelMaintenance))) { + _storagePoolWorkDao.removePendingJobsOnMsRestart(vo.getMsid(), poolId); + pool.setStatus(StoragePoolStatus.ErrorInMaintenance); + _storagePoolDao.update(poolId, pool); + } + + } + } + } + } + } + } diff --git a/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java b/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java index e116be2a947..de9a1a87d09 100644 --- a/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java +++ b/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java @@ -39,6 +39,7 @@ import com.cloud.server.StatsCollector; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; +import com.cloud.storage.StoragePoolStatus; import com.cloud.storage.StoragePoolVO; import com.cloud.storage.StorageStats; import com.cloud.storage.VMTemplateHostVO; @@ -139,7 +140,7 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement //by default, all pools are up when successfully added //don't return the pool if not up (if in maintenance/prepareformaintenance/errorinmaintenance) - if(!pool.getStatus().equals(com.cloud.host.Status.Up)) + if(!pool.getStatus().equals(StoragePoolStatus.Up)) return false; // Check that the pool type is correct diff --git a/server/src/com/cloud/storage/dao/StoragePoolDao.java b/server/src/com/cloud/storage/dao/StoragePoolDao.java index 06d10c88b8a..6b90267fe32 100644 --- a/server/src/com/cloud/storage/dao/StoragePoolDao.java +++ b/server/src/com/cloud/storage/dao/StoragePoolDao.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.Map; import com.cloud.host.Status; +import com.cloud.storage.StoragePoolStatus; import com.cloud.storage.StoragePoolVO; import com.cloud.utils.db.GenericDao; /** @@ -104,6 +105,5 @@ public interface StoragePoolDao extends GenericDao { List findIfDuplicatePoolsExistByUUID(String uuid); - List listPoolsByStatus(Status status); - + List listPoolsByStatus(StoragePoolStatus status); } diff --git a/server/src/com/cloud/storage/dao/StoragePoolDaoImpl.java b/server/src/com/cloud/storage/dao/StoragePoolDaoImpl.java index 5c0c18b8c5a..54e7647e61a 100644 --- a/server/src/com/cloud/storage/dao/StoragePoolDaoImpl.java +++ b/server/src/com/cloud/storage/dao/StoragePoolDaoImpl.java @@ -31,6 +31,7 @@ import javax.naming.ConfigurationException; import com.cloud.host.Status; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StoragePoolDetailVO; +import com.cloud.storage.StoragePoolStatus; import com.cloud.storage.StoragePoolVO; import com.cloud.utils.component.ComponentLocator; import com.cloud.utils.db.DB; @@ -185,7 +186,7 @@ public class StoragePoolDaoImpl extends GenericDaoBase imp } @Override - public List listPoolsByStatus(Status status){ + public List listPoolsByStatus(StoragePoolStatus status){ SearchCriteria sc = StatusSearch.create(); sc.setParameters("status", status); return listBy(sc); diff --git a/server/src/com/cloud/storage/dao/StoragePoolWorkDao.java b/server/src/com/cloud/storage/dao/StoragePoolWorkDao.java new file mode 100644 index 00000000000..1d9bdae82c7 --- /dev/null +++ b/server/src/com/cloud/storage/dao/StoragePoolWorkDao.java @@ -0,0 +1,39 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.cloud.storage.dao; + +import java.util.List; + +import com.cloud.storage.StoragePoolWorkVO; +import com.cloud.utils.db.GenericDao; +/** + * Data Access Object for storage_pool table + */ +public interface StoragePoolWorkDao extends GenericDao { + + List listPendingWorkForPrepareForMaintenanceByPoolId(long poolId); + + List listPendingWorkForCancelMaintenanceByPoolId(long poolId); + + StoragePoolWorkVO findByPoolIdAndVmId(long poolId, long vmId); + + void removePendingJobsOnMsRestart(long msId, long poolId); + + List searchForPoolIdsForPendingWorkJobs(long msId); + +} diff --git a/server/src/com/cloud/storage/dao/StoragePoolWorkDaoImpl.java b/server/src/com/cloud/storage/dao/StoragePoolWorkDaoImpl.java new file mode 100644 index 00000000000..d32efd7b62c --- /dev/null +++ b/server/src/com/cloud/storage/dao/StoragePoolWorkDaoImpl.java @@ -0,0 +1,134 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.cloud.storage.dao; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import javax.ejb.Local; + +import com.cloud.storage.StoragePoolWorkVO; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; + +@Local(value={StoragePoolWorkDao.class}) @DB(txn=false) +public class StoragePoolWorkDaoImpl extends GenericDaoBase implements StoragePoolWorkDao { + + protected final SearchBuilder PendingWorkForPrepareForMaintenanceSearch; + protected final SearchBuilder PendingWorkForCancelMaintenanceSearch; + protected final SearchBuilder PoolAndVmIdSearch; + protected final SearchBuilder PendingJobsForDeadMs; + + private final String FindPoolIds = "SELECT distinct storage_pool_work.pool_id FROM storage_pool_work WHERE mgmt_server_id = ?"; + + protected StoragePoolWorkDaoImpl() { + PendingWorkForPrepareForMaintenanceSearch = createSearchBuilder(); + PendingWorkForPrepareForMaintenanceSearch.and("poolId", PendingWorkForPrepareForMaintenanceSearch.entity().getPoolId(), SearchCriteria.Op.EQ); + PendingWorkForPrepareForMaintenanceSearch.and("stoppedForMaintenance", PendingWorkForPrepareForMaintenanceSearch.entity().isStoppedForMaintenance(), SearchCriteria.Op.EQ); + PendingWorkForPrepareForMaintenanceSearch.and("startedAfterMaintenance", PendingWorkForPrepareForMaintenanceSearch.entity().isStartedAfterMaintenance(), SearchCriteria.Op.EQ); + PendingWorkForPrepareForMaintenanceSearch.done(); + + PendingWorkForCancelMaintenanceSearch = createSearchBuilder(); + PendingWorkForCancelMaintenanceSearch.and("poolId", PendingWorkForCancelMaintenanceSearch.entity().getPoolId(), SearchCriteria.Op.EQ); + PendingWorkForCancelMaintenanceSearch.and("stoppedForMaintenance", PendingWorkForCancelMaintenanceSearch.entity().isStoppedForMaintenance(), SearchCriteria.Op.EQ); + PendingWorkForCancelMaintenanceSearch.and("startedAfterMaintenance", PendingWorkForCancelMaintenanceSearch.entity().isStartedAfterMaintenance(), SearchCriteria.Op.EQ); + PendingWorkForCancelMaintenanceSearch.done(); + + PoolAndVmIdSearch = createSearchBuilder(); + PoolAndVmIdSearch.and("poolId", PoolAndVmIdSearch.entity().getPoolId(), SearchCriteria.Op.EQ); + PoolAndVmIdSearch.and("vmId", PoolAndVmIdSearch.entity().getVmId(), SearchCriteria.Op.EQ); + PoolAndVmIdSearch.done(); + + PendingJobsForDeadMs = createSearchBuilder(); + PendingJobsForDeadMs.and("managementServerId", PendingJobsForDeadMs.entity().getManagementServerId(), SearchCriteria.Op.EQ); + PendingJobsForDeadMs.and("poolId", PendingJobsForDeadMs.entity().getPoolId(), SearchCriteria.Op.EQ); + PendingJobsForDeadMs.and("stoppedForMaintenance", PendingJobsForDeadMs.entity().isStoppedForMaintenance(), SearchCriteria.Op.EQ); + PendingJobsForDeadMs.and("startedAfterMaintenance", PendingJobsForDeadMs.entity().isStartedAfterMaintenance(), SearchCriteria.Op.EQ); + PendingJobsForDeadMs.done(); + + } + + @Override + public List listPendingWorkForPrepareForMaintenanceByPoolId(long poolId) { + SearchCriteria sc = PendingWorkForPrepareForMaintenanceSearch.create(); + sc.setParameters("poolId", poolId); + sc.setParameters("stoppedForMaintenance", false); + sc.setParameters("startedAfterMaintenance", false); + return listBy(sc); + } + + @Override + public List listPendingWorkForCancelMaintenanceByPoolId(long poolId) { + SearchCriteria sc = PendingWorkForCancelMaintenanceSearch.create(); + sc.setParameters("poolId", poolId); + sc.setParameters("stoppedForMaintenance", true); + sc.setParameters("startedAfterMaintenance", false); + return listBy(sc); + } + + @Override + public StoragePoolWorkVO findByPoolIdAndVmId(long poolId, long vmId) { + SearchCriteria sc = PoolAndVmIdSearch.create(); + sc.setParameters("poolId", poolId); + sc.setParameters("vmId", vmId); + return listBy(sc).get(0); + } + + @Override + public void removePendingJobsOnMsRestart(long msId, long poolId) { + //hung jobs are those which are stopped, but never started + SearchCriteria sc = PendingJobsForDeadMs.create(); + sc.setParameters("managementServerId", msId); + sc.setParameters("poolId", poolId); + sc.setParameters("stoppedForMaintenance", true); + sc.setParameters("startedAfterMaintenance", false); + remove(sc); + } + + @Override + @DB + public List searchForPoolIdsForPendingWorkJobs(long msId){ + + StringBuilder sql = new StringBuilder(FindPoolIds); + + Transaction txn = Transaction.currentTxn(); + PreparedStatement pstmt = null; + try { + pstmt = txn.prepareAutoCloseStatement(sql.toString()); + pstmt.setLong(1, msId); + + ResultSet rs = pstmt.executeQuery(); + List poolIds = new ArrayList(); + + while (rs.next()) { + poolIds.add(rs.getLong("pool_id")); + } + return poolIds; + } catch (SQLException e) { + throw new CloudRuntimeException("Unable to execute " + pstmt.toString(), e); + } + + } +} diff --git a/server/src/com/cloud/storage/dao/VolumeDaoImpl.java b/server/src/com/cloud/storage/dao/VolumeDaoImpl.java index 5cba1248ec2..62a9d2181c6 100755 --- a/server/src/com/cloud/storage/dao/VolumeDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VolumeDaoImpl.java @@ -122,6 +122,7 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("poolId", poolId); sc.setParameters("notDestroyed", Volume.State.Destroy); + sc.setParameters("vType", Volume.VolumeType.ROOT.toString()); return listBy(sc); } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 65e8109bc79..2238b99ea7e 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -133,6 +133,11 @@ import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.GuestOSVO; import com.cloud.storage.SnapshotVO; import com.cloud.storage.Storage; +import com.cloud.storage.StoragePoolStatus; +import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.Storage.StorageResourceType; +import com.cloud.storage.Storage.TemplateType; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePoolVO; import com.cloud.storage.VMTemplateHostVO; @@ -1906,7 +1911,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager _accountMgr.checkAccess(owner, domain); } //check if we have available pools for vm deployment - List availablePools = _storagePoolDao.listPoolsByStatus(com.cloud.host.Status.Up); + List availablePools = _storagePoolDao.listPoolsByStatus(StoragePoolStatus.Up); if( availablePools == null || availablePools.size() < 1) { throw new StorageUnavailableException("There are no available pools in the UP state for vm deployment",-1); diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index fb05f09d9b5..b10b4425b73 100644 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -559,7 +559,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, StateLi long vmId = vm.getId(); VirtualMachineGuru vmGuru = getVmGuru(vm); - + vm = vmGuru.findById(vm.getId()); Ternary start = changeToStartState(vmGuru, vm, caller, account); if (start == null) { return vmGuru.findById(vmId); diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 3a989dd9cad..5339efc93db 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -1385,4 +1385,15 @@ CREATE TABLE `cloud`.`ovs_work` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE `cloud`.`storage_pool_work` ( + `id` bigint unsigned UNIQUE NOT NULL AUTO_INCREMENT COMMENT 'id', + `pool_id` bigint unsigned NOT NULL COMMENT 'storage pool associated with the vm', + `vm_id` bigint unsigned NOT NULL COMMENT 'vm identifier', + `stopped_for_maintenance` tinyint unsigned NOT NULL DEFAULT 0 COMMENT 'this flag denoted whether the vm was stopped during maintenance', + `started_after_maintenance` tinyint unsigned NOT NULL DEFAULT 0 COMMENT 'this flag denoted whether the vm was started after maintenance', + `mgmt_server_id` bigint unsigned NOT NULL COMMENT 'management server id', + PRIMARY KEY (`id`), + UNIQUE (pool_id,vm_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + SET foreign_key_checks = 1;