package org.ovirt.engine.core.bll.storage; import java.util.List; import org.ovirt.engine.core.bll.Backend; import org.ovirt.engine.core.bll.NonTransactiveCommandAttribute; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.action.StorageDomainPoolParametersBase; import org.ovirt.engine.core.common.businessentities.AsyncTaskStatus; import org.ovirt.engine.core.common.businessentities.StorageDomainStatus; import org.ovirt.engine.core.common.businessentities.StorageDomainType; import org.ovirt.engine.core.common.businessentities.StoragePoolIsoMapId; import org.ovirt.engine.core.common.businessentities.StoragePoolStatus; import org.ovirt.engine.core.common.businessentities.VDS; import org.ovirt.engine.core.common.businessentities.storage_domains; import org.ovirt.engine.core.common.businessentities.storage_pool_iso_map; import org.ovirt.engine.core.common.errors.VdcBLLException; import org.ovirt.engine.core.common.errors.VdcBllErrors; import org.ovirt.engine.core.common.vdscommands.DeactivateStorageDomainVDSCommandParameters; import org.ovirt.engine.core.common.vdscommands.DisconnectStoragePoolVDSCommandParameters; import org.ovirt.engine.core.common.vdscommands.IrsBaseVDSCommandParameters; import org.ovirt.engine.core.common.vdscommands.VDSCommandType; import org.ovirt.engine.core.common.vdscommands.VDSReturnValue; import org.ovirt.engine.core.common.vdscommands.VdsIdVDSCommandParametersBase; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.compat.LogCompat; import org.ovirt.engine.core.compat.LogFactoryCompat; import org.ovirt.engine.core.dal.VdcBllMessages; import org.ovirt.engine.core.dal.dbbroker.DbFacade; import org.ovirt.engine.core.utils.linq.LinqUtils; import org.ovirt.engine.core.utils.linq.Predicate; import org.ovirt.engine.core.utils.transaction.TransactionMethod; import org.ovirt.engine.core.utils.transaction.TransactionSupport; @NonTransactiveCommandAttribute(forceCompensation = true) public class DeactivateStorageDomainCommand<T extends StorageDomainPoolParametersBase> extends StorageDomainCommandBase<T> { protected Guid _newMasterStorageDomainId = new Guid(); private storage_domains _newMaster; protected storage_domains getNewMaster() { if (_newMaster == null && _newMasterStorageDomainId.equals(Guid.Empty)) { _newMaster = electNewMaster(); } else if (_newMaster == null) { _newMaster = DbFacade.getInstance().getStorageDomainDAO().get(_newMasterStorageDomainId); } return _newMaster; } protected void setNewMaster(storage_domains value) { _newMaster = value; } protected boolean _isLastMaster; private VDS spm; public DeactivateStorageDomainCommand(T parameters) { super(parameters); } /** * Constructor for command creation when compensation is applied on startup * * @param commandId */ protected DeactivateStorageDomainCommand(Guid commandId) { super(commandId); } @Override protected boolean canDoAction() { super.canDoAction(); addCanDoActionMessage(VdcBllMessages.VAR__ACTION__DEACTIVATE); if (!(CheckStorageDomain() && checkStorageDomainStatus(StorageDomainStatus.Active))) { return false; } if (!getParameters().getIsInternal() && getStorageDomain().getstorage_domain_type() == StorageDomainType.Master) { List<storage_domains> domains = DbFacade.getInstance().getStorageDomainDAO().getAllForStoragePool( getStorageDomain().getstorage_pool_id().getValue()); List<storage_domains> activeDomains = filterDomainsByStatus(domains, StorageDomainStatus.Active); List<storage_domains> dataDomains = LinqUtils.filter(activeDomains, new Predicate<storage_domains>() { @Override public boolean eval(storage_domains a) { return a.getstorage_domain_type() == StorageDomainType.Data; } }); if (!activeDomains.isEmpty() && dataDomains.isEmpty()) { addCanDoActionMessage(VdcBllMessages.ERROR_CANNOT_DEACTIVATE_MASTER_WITH_NON_DATA_DOMAINS); return false; } if (!filterDomainsByStatus(domains, StorageDomainStatus.Locked).isEmpty()) { addCanDoActionMessage(VdcBllMessages.ERROR_CANNOT_DEACTIVATE_MASTER_WITH_LOCKED_DOMAINS); return false; } } if (!getParameters().getIsInternal() && !DbFacade.getInstance() .getVmDAO() .getAllRunningForStorageDomain(getStorageDomain().getid()) .isEmpty()) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_DETECTED_RUNNING_VMS); return false; } try { if (getStoragePool().getspm_vds_id() != null && getStorageDomain().getstorage_domain_type() != StorageDomainType.ISO && !((java.util.HashMap<Guid, AsyncTaskStatus>) Backend .getInstance() .getResourceManager() .RunVdsCommand(VDSCommandType.HSMGetAllTasksStatuses, new VdsIdVDSCommandParametersBase(getStoragePool().getspm_vds_id().getValue())) .getReturnValue()).isEmpty()) { addCanDoActionMessage(VdcBllMessages.ERROR_CANNOT_DEACTIVATE_DOMAIN_WITH_TASKS); return false; } } catch (VdcBLLException e) { if (e.getErrorCode() == VdcBllErrors.VDS_NETWORK_ERROR) { addCanDoActionMessage(VdcBllMessages.STORAGE_OPERATION_FAILED_SPM_NETWORK_PROBLEMS); } else { throw e; } return false; } return true; } /** * Filter out the domains with the requested status from the given domains list, excluding the domain which the * command is run for. * * @param domains * The domains to filter. * @param domainStatus * The status to filter by. * @return Just the domains that match the given status, excluding the current domain of the command. */ private List<storage_domains> filterDomainsByStatus(List<storage_domains> domains, final StorageDomainStatus domainStatus) { List<storage_domains> activeDomains = LinqUtils.filter(domains, new Predicate<storage_domains>() { @Override public boolean eval(storage_domains a) { return a.getstatus() == domainStatus && !a.getid().equals(getStorageDomain().getid()); } }); return activeDomains; } @Override protected void executeCommand() { spm = null; if (getStoragePool().getspm_vds_id() != null) { spm = DbFacade.getInstance().getVdsDAO().get(getStoragePool().getspm_vds_id()); } final storage_pool_iso_map map = DbFacade.getInstance() .getStoragePoolIsoMapDAO() .get(new StoragePoolIsoMapId(getParameters().getStorageDomainId(), getParameters().getStoragePoolId())); changeStorageDomainStatusInTransaction(map, StorageDomainStatus.Locked); ProceedStorageDomainTreatmentByDomainType(false); if (_isLastMaster) { TransactionSupport.executeInNewTransaction(new TransactionMethod<Object>() { @Override public Object runInTransaction() { getCompensationContext().snapshotEntityStatus(getStoragePool(), getStoragePool().getstatus()); getStoragePool().setstatus(StoragePoolStatus.Maintanance); DbFacade.getInstance() .getStoragePoolDAO() .updateStatus(getStoragePool().getId(), getStoragePool().getstatus()); getCompensationContext().stateChanged(); return null; } }); StoragePoolStatusHandler.PoolStatusChanged(getStoragePool().getId(), getStoragePool().getstatus()); runSynchronizeOperation(new DisconnectStoragePoolAsyncOperationFactory()); getStorageDomain().getStorageDynamicData().setavailable_disk_size(null); getStorageDomain().getStorageDynamicData().setused_disk_size(null); } boolean succeeded = Backend.getInstance() .getResourceManager() .RunVdsCommand( VDSCommandType.DeactivateStorageDomain, new DeactivateStorageDomainVDSCommandParameters(getStoragePool().getId(), getStorageDomain() .getid(), _newMasterStorageDomainId, getStoragePool().getmaster_domain_version())) .getSucceeded(); if (succeeded) { runSynchronizeOperation(new AfterDeactivateSingleAsyncOperationFactory(), _isLastMaster, _newMasterStorageDomainId); if (_isLastMaster && spm != null) { final VDSReturnValue stopSpmReturnValue = Backend.getInstance() .getResourceManager() .RunVdsCommand(VDSCommandType.SpmStopOnIrs, new IrsBaseVDSCommandParameters(getStoragePool().getId())); if (!stopSpmReturnValue.getSucceeded()) { // no need to continue because DisconnectStoragePool will // fail if host is SPM log.error("Aborting execution due to failure stopping SPM." + " Stop SPM failed due to " + stopSpmReturnValue.getExceptionString()); setSucceeded(false); return; } Backend.getInstance() .getResourceManager() .RunVdsCommand( VDSCommandType.DisconnectStoragePool, new DisconnectStoragePoolVDSCommandParameters(spm.getvds_id(), getStoragePool().getId(), spm.getvds_spm_id())); } StorageHelperDirector.getInstance().getItem(getStorageDomain().getstorage_type()) .DisconnectStorageFromDomainByVdsId(getStorageDomain(), spm.getvds_id()); TransactionSupport.executeInNewTransaction(new TransactionMethod<Object>() { @Override public Object runInTransaction() { getCompensationContext().snapshotEntityStatus(map, map.getstatus()); map.setstatus(StorageDomainStatus.InActive); DbFacade.getInstance().getStoragePoolIsoMapDAO().updateStatus(map.getId(), map.getstatus()); if (!Guid.Empty.equals(_newMasterStorageDomainId)) { storage_pool_iso_map mapOfNewMaster = getNewMaster().getStoragePoolIsoMapData(); getCompensationContext().snapshotEntityStatus(mapOfNewMaster, mapOfNewMaster.getstatus()); mapOfNewMaster.setstatus(StorageDomainStatus.Active); DbFacade.getInstance() .getStoragePoolIsoMapDAO() .updateStatus(mapOfNewMaster.getId(), mapOfNewMaster.getstatus()); } getCompensationContext().stateChanged(); return null; } }); setSucceeded(true); } } /* * In case of master domain this method decide if to move master to other domain or move pool to maintenance (since * there is no master domain) * * @param duringReconstruct If true storagePool will be saved to DB outside of the transaction and master domain * will not be locked */ protected void ProceedStorageDomainTreatmentByDomainType(final boolean duringReconstruct) { if (getStorageDomain().getstorage_domain_type() == StorageDomainType.Master) { if (getNewMaster() != null) { // increase master domain version TransactionSupport.executeInNewTransaction(new TransactionMethod<Object>() { @Override public Object runInTransaction() { storage_pool_iso_map newMasterMap = getNewMaster().getStoragePoolIsoMapData(); // We do not need to compensate storage pool, it will be committed if run during reconstruct getStoragePool().setmaster_domain_version(getStoragePool().getmaster_domain_version() + 1); getCompensationContext().snapshotEntity(getNewMaster().getStorageStaticData()); getNewMaster().setstorage_domain_type(StorageDomainType.Master); _newMasterStorageDomainId = getNewMaster().getid(); if (!duringReconstruct) { getCompensationContext().snapshotEntityStatus(newMasterMap, newMasterMap.getstatus()); getNewMaster().setstatus(StorageDomainStatus.Locked); DbFacade.getInstance() .getStoragePoolIsoMapDAO() .updateStatus(newMasterMap.getId(), newMasterMap.getstatus()); } DbFacade.getInstance() .getStorageDomainStaticDAO() .update(getNewMaster().getStorageStaticData()); getCompensationContext().snapshotEntity(getStorageDomain().getStorageStaticData()); getStorageDomain().setstorage_domain_type(StorageDomainType.Data); DbFacade.getInstance() .getStorageDomainStaticDAO() .update(getStorageDomain().getStorageStaticData()); getCompensationContext().stateChanged(); return null; } }); } else { _isLastMaster = true; } updateStoragePoolInDiffTransaction(); } } @Override public AuditLogType getAuditLogTypeValue() { return getParameters().getIsInternal() ? getSucceeded() ? AuditLogType.SYSTEM_DEACTIVATED_STORAGE_DOMAIN : AuditLogType.SYSTEM_DEACTIVATE_STORAGE_DOMAIN_FAILED : getSucceeded() ? AuditLogType.USER_DEACTIVATED_STORAGE_DOMAIN : AuditLogType.USER_DEACTIVATE_STORAGE_DOMAIN_FAILED; } private static LogCompat log = LogFactoryCompat.getLog(DeactivateStorageDomainCommand.class); }