diff --git a/server/src/com/cloud/api/BaseCmd.java b/server/src/com/cloud/api/BaseCmd.java index 627e9626045..bb1335bf88a 100755 --- a/server/src/com/cloud/api/BaseCmd.java +++ b/server/src/com/cloud/api/BaseCmd.java @@ -82,6 +82,7 @@ public abstract class BaseCmd { public static final int NET_LIST_ERROR = 570; public static final int CUSTOM_CERT_UPDATE_ERROR = 571; public static final int PREPARE_STORAGE_MAINTENANCE_ERROR = 572; + public static final int CANCEL_STORAGE_MAINTENANCE_ERROR = 573; public static final int STORAGE_RESOURCE_IN_USE = 580; public static final DateFormat INPUT_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index fa5465d8c4a..4c3d8ea99b1 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -2349,133 +2349,143 @@ public class StorageManagerImpl implements StorageManager { @Override @DB - public StoragePoolVO cancelPrimaryStorageForMaintenance(CancelPrimaryStorageMaintenanceCmd cmd) throws InvalidParameterValueException{ + public synchronized StoragePoolVO cancelPrimaryStorageForMaintenance(CancelPrimaryStorageMaintenanceCmd cmd) throws InvalidParameterValueException{ Long primaryStorageId = cmd.getId(); Long userId = UserContext.current().getUserId(); - - //1. Get the primary storage record and perform validation check - StoragePoolVO primaryStorage = _storagePoolDao.findById(primaryStorageId); - - if(primaryStorage == null) - { - s_logger.warn("The primary storage does not exist"); - throw new InvalidParameterValueException("Primary storage doesn't exist"); - } - - if (!primaryStorage.getStatus().equals(Status.Maintenance)) { - throw new InvalidParameterValueException("Primary storage with id " + primaryStorageId + " is not ready for migration, as the status is:" + primaryStorage.getStatus().toString()); - } - - //2. Get a list of all the volumes within this storage pool - List allVolumes = _volsDao.findByPoolId(primaryStorageId); + 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 ResourceUnavailableException(msg); + } + + if (!primaryStorage.getStatus().equals(Status.Maintenance)) { + throw new InvalidParameterValueException("Primary storage with id " + primaryStorageId + " is not ready to complete migration, as the status is:" + primaryStorage.getStatus().toString()); + } + + //2. Get a list of all the volumes within this storage pool + List allVolumes = _volsDao.findByPoolId(primaryStorageId); - //3. If the volume is not removed AND not destroyed, start the vm corresponding to it - for(VolumeVO volume: allVolumes) - { - if((!volume.destroyed) && (volume.removed==null)) - { - VMInstanceVO vmInstance = _vmInstanceDao.findById(volume.getInstanceId()); - - if(vmInstance.getState().equals(State.Stopping) || vmInstance.getState().equals(State.Stopped)) - { - //if the instance is of type consoleproxy, call the console proxy - if(vmInstance.getType().equals(VirtualMachine.Type.ConsoleProxy)) - { - - //create a dummy event - long eventId = saveScheduledEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, EventTypes.EVENT_PROXY_START, "starting console proxy with Id: "+vmInstance.getId()); - - if(_consoleProxyMgr.startProxy(vmInstance.getId(), eventId)==null) - { - s_logger.warn("There was an error starting the console proxy id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"); - primaryStorage.setStatus(Status.ErrorInMaintenance); - _storagePoolDao.persist(primaryStorage); - return primaryStorage; - } - } - - //if the instance is of type ssvm, call the ssvm manager - if(vmInstance.getType().equals(VirtualMachine.Type.SecondaryStorageVm)) - { - - //create a dummy event - long eventId = saveScheduledEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, EventTypes.EVENT_SSVM_START, "starting ssvm with Id: "+vmInstance.getId()); - - if(_secStorageMgr.startSecStorageVm(vmInstance.getId(), eventId)==null) - { - s_logger.warn("There was an error starting the ssvm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"); - primaryStorage.setStatus(Status.ErrorInMaintenance); - _storagePoolDao.persist(primaryStorage); - return primaryStorage; - } - } - - //if the instance is of type user vm, call the user vm manager - if(vmInstance.getType().equals(VirtualMachine.Type.User)) - { - - //create a dummy event - long eventId = saveScheduledEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, EventTypes.EVENT_VM_START, "starting ssvm with Id: "+vmInstance.getId()); - - try { - if(_userVmMgr.start(vmInstance.getId(), eventId)==null) + //3. If the volume is not removed AND not destroyed, start the vm corresponding to it + for(VolumeVO volume: allVolumes) + { + if((!volume.destroyed) && (volume.removed==null)) + { + VMInstanceVO vmInstance = _vmInstanceDao.findById(volume.getInstanceId()); + + if(vmInstance.getState().equals(State.Stopping) || vmInstance.getState().equals(State.Stopped)) + { + //if the instance is of type consoleproxy, call the console proxy + if(vmInstance.getType().equals(VirtualMachine.Type.ConsoleProxy)) + { + + //create a dummy event + long eventId = saveScheduledEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, EventTypes.EVENT_PROXY_START, "starting console proxy with Id: "+vmInstance.getId()); + + if(_consoleProxyMgr.startProxy(vmInstance.getId(), eventId)==null) { - s_logger.warn("There was an error starting the ssvm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"); - primaryStorage.setStatus(Status.ErrorInMaintenance); - _storagePoolDao.persist(primaryStorage); - return primaryStorage; + 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 ResourceUnavailableException(msg); } - } catch (StorageUnavailableException e) { - s_logger.warn("There was an error starting the ssvm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"); - s_logger.warn(e); - primaryStorage.setStatus(Status.ErrorInMaintenance); - _storagePoolDao.persist(primaryStorage); - return primaryStorage; - } catch (InsufficientCapacityException e) { - s_logger.warn("There was an error starting the ssvm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"); - s_logger.warn(e); - primaryStorage.setStatus(Status.ErrorInMaintenance); - _storagePoolDao.persist(primaryStorage); - return primaryStorage; - } catch (ConcurrentOperationException e) { - s_logger.warn("There was an error starting the ssvm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"); - s_logger.warn(e); - primaryStorage.setStatus(Status.ErrorInMaintenance); - _storagePoolDao.persist(primaryStorage); - return primaryStorage; - } catch (ExecutionException e) { - s_logger.warn("There was an error starting the ssvm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"); - s_logger.warn(e); - primaryStorage.setStatus(Status.ErrorInMaintenance); - _storagePoolDao.persist(primaryStorage); - return primaryStorage; } - } - - } - } - } - - //Restore config val for consoleproxy.restart to true - try { - _configMgr.updateConfiguration(userId, "consoleproxy.restart", "true"); - } catch (InvalidParameterValueException e) { - s_logger.warn("Error changing consoleproxy.restart back to false at end of cancel maintenance:"+e); - primaryStorage.setStatus(Status.ErrorInMaintenance); - _storagePoolDao.persist(primaryStorage); - return primaryStorage; - } catch (CloudRuntimeException e) { - s_logger.warn("Error changing consoleproxy.restart back to false at end of cancel maintenance:"+e); - primaryStorage.setStatus(Status.ErrorInMaintenance); - _storagePoolDao.persist(primaryStorage); + + //if the instance is of type ssvm, call the ssvm manager + if(vmInstance.getType().equals(VirtualMachine.Type.SecondaryStorageVm)) + { + + //create a dummy event + long eventId = saveScheduledEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, EventTypes.EVENT_SSVM_START, "starting ssvm with Id: "+vmInstance.getId()); + + if(_secStorageMgr.startSecStorageVm(vmInstance.getId(), eventId)==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 ResourceUnavailableException(msg); + } + } + + //if the instance is of type user vm, call the user vm manager + if(vmInstance.getType().equals(VirtualMachine.Type.User)) + { + + //create a dummy event + long eventId = saveScheduledEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, EventTypes.EVENT_VM_START, "starting ssvm with Id: "+vmInstance.getId()); + + try { + if(_userVmMgr.start(vmInstance.getId(), eventId)==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 ResourceUnavailableException(msg); + } + } catch (StorageUnavailableException e) { + String msg = "There was an error starting the ssvm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"; + s_logger.warn(msg,e); + throw new ResourceUnavailableException(msg); + } catch (InsufficientCapacityException e) { + String msg = "There was an error starting the ssvm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"; + s_logger.warn(msg,e); + throw new ResourceUnavailableException(msg); + } catch (ConcurrentOperationException e) { + String msg = "There was an error starting the ssvm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"; + s_logger.warn(msg,e); + primaryStorage.setStatus(Status.ErrorInMaintenance); + _storagePoolDao.persist(primaryStorage); + throw new ResourceUnavailableException(msg); + } catch (ExecutionException e) { + String msg = "There was an error starting the ssvm id: "+vmInstance.getId()+" on storage pool, cannot complete primary storage maintenance"; + s_logger.warn(msg,e); + throw new ResourceUnavailableException(msg); + } + } + + } + } + } + + //Restore config val for consoleproxy.restart to true + try { + _configMgr.updateConfiguration(userId, "consoleproxy.restart", "true"); + } catch (InvalidParameterValueException e) { + String msg = "Error changing consoleproxy.restart back to false at end of cancel maintenance:"; + s_logger.warn(msg,e); + throw new ResourceUnavailableException(msg); + } catch (CloudRuntimeException e) { + String msg = "Error changing consoleproxy.restart back to false at end of cancel maintenance:"; + s_logger.warn(msg,e); + throw new ResourceUnavailableException(msg); + } + + //Change the storage state back to up + primaryStorage.setStatus(Status.Up); + _storagePoolDao.persist(primaryStorage); + return primaryStorage; + } catch (Exception e) { + if(e instanceof ResourceUnavailableException){ + primaryStorage.setStatus(Status.ErrorInMaintenance); + _storagePoolDao.persist(primaryStorage); + throw new ServerApiException(BaseCmd.CANCEL_STORAGE_MAINTENANCE_ERROR, e.getMessage()); + } + else if(e instanceof InvalidParameterValueException){ + primaryStorage.setStatus(Status.ErrorInMaintenance); + _storagePoolDao.persist(primaryStorage); + throw new ServerApiException(BaseCmd.CANCEL_STORAGE_MAINTENANCE_ERROR, e.getMessage()); + } + else{//all other exceptions + primaryStorage.setStatus(Status.ErrorInMaintenance); + _storagePoolDao.persist(primaryStorage); + throw new ServerApiException(BaseCmd.CANCEL_STORAGE_MAINTENANCE_ERROR, e.getMessage()); + } + }finally{ + _storagePoolDao.releaseFromLockTable(primaryStorage.getId()); } - - //Change the storage state back to up - primaryStorage.setStatus(Status.Up); - _storagePoolDao.persist(primaryStorage); - - return primaryStorage; } private boolean sendToVmResidesOn(StoragePoolVO storagePool, Command cmd) { diff --git a/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java b/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java index 1c3555f5ea6..49cb5d717b8 100644 --- a/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java +++ b/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java @@ -136,8 +136,12 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement if(dskCh.getType().equals(VolumeType.ROOT) && pool.getPoolType().equals(StoragePoolType.Iscsi)){ return false; } - - + + //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)) + return false; + // Check that the pool type is correct if (!poolIsCorrectType(dskCh, pool, vm)) { return false;