package org.ovirt.engine.core.bll.storage; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.ovirt.engine.core.bll.Backend; import org.ovirt.engine.core.bll.CommandBase; import org.ovirt.engine.core.common.VdcObjectType; import org.ovirt.engine.core.common.action.StoragePoolParametersBase; import org.ovirt.engine.core.common.businessentities.IVdcQueryable; import org.ovirt.engine.core.common.businessentities.StorageDomainSharedStatus; import org.ovirt.engine.core.common.businessentities.StorageDomainStatus; import org.ovirt.engine.core.common.businessentities.StorageDomainType; import org.ovirt.engine.core.common.businessentities.StorageFormatType; 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; import org.ovirt.engine.core.common.config.Config; import org.ovirt.engine.core.common.config.ConfigValues; import org.ovirt.engine.core.common.interfaces.SearchType; import org.ovirt.engine.core.common.queries.SearchParameters; import org.ovirt.engine.core.common.queries.VdcQueryType; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.compat.TransactionScopeOption; import org.ovirt.engine.core.compat.Version; import org.ovirt.engine.core.dal.VdcBllMessages; import org.ovirt.engine.core.dal.dbbroker.DbFacade; import org.ovirt.engine.core.utils.SyncronizeNumberOfAsyncOperations; import org.ovirt.engine.core.utils.linq.All; 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; public abstract class StorageHandlingCommandBase<T extends StoragePoolParametersBase> extends CommandBase<T> { public StorageHandlingCommandBase(T parameters) { super(parameters); if (getParameters() != null && !getParameters().getStoragePoolId().equals(Guid.Empty)) { setStoragePoolId(getParameters().getStoragePoolId()); } } /** * Constructor for command creation when compensation is applied on startup * * @param commandId */ protected StorageHandlingCommandBase(Guid commandId) { super(commandId); } public static final String UpVdssInStoragePoolQuery = "HOST: status = UP and DATACENTER = {0}"; public static final String UpVdssInCluster = "HOST: status = UP and CLUSTER = {0}"; public static final String DesktopsInStoragePoolQuery = "VMS: DATACENTER = {0}"; public static List<VDS> GetAllRunningVdssInPool(storage_pool pool) { java.util.ArrayList<VDS> returnValue = new java.util.ArrayList<VDS>(); SearchParameters p = new SearchParameters(MessageFormat.format(UpVdssInStoragePoolQuery, pool.getname()), SearchType.VDS); p.setMaxCount(Integer.MAX_VALUE); Iterable<IVdcQueryable> fromVds = (Iterable<IVdcQueryable>) (Backend.getInstance().runInternalQuery( VdcQueryType.Search, p).getReturnValue()); if (fromVds != null) { for (IVdcQueryable vds : fromVds) { if (vds instanceof VDS) { returnValue.add((VDS) vds); } } } return returnValue; } protected void updateStoragePoolInDiffTransaction() { TransactionSupport.executeInScope(TransactionScopeOption.Suppress, new TransactionMethod<Object>() { @Override public Object runInTransaction() { DbFacade.getInstance().getStoragePoolDAO().update(getStoragePool()); return null; } }); } protected List<VDS> getAllRunningVdssInPool() { return GetAllRunningVdssInPool(getStoragePool()); } protected Guid getMasterDomainIdFromDb() { if (getStoragePool() != null) { return DbFacade.getInstance() .getStorageDomainDAO() .getMasterStorageDomainIdForPool(getStoragePool().getId()); } else { return Guid.Empty; } } protected boolean InitializeVds() { boolean returnValue = true; if (getVds() == null) { SearchParameters p = new SearchParameters(MessageFormat.format(UpVdssInStoragePoolQuery, getStoragePool() .getname()), SearchType.VDS); p.setMaxCount(Integer.MAX_VALUE); Object tempVar = LinqUtils.firstOrNull((List) Backend.getInstance() .runInternalQuery(VdcQueryType.Search, p).getReturnValue(), new All()); setVds(((VDS) ((tempVar instanceof VDS) ? tempVar : null))); if (getVds() == null) { returnValue = false; addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_NO_VDS_IN_POOL); } } return returnValue; } protected boolean CheckStoragePool() { boolean returnValue = false; if (getStoragePool() != null) { returnValue = DbFacade.getInstance().getStoragePoolDAO().get(getStoragePool().getId()) != null; } if (!returnValue) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_STORAGE_POOL_NOT_EXIST); } return returnValue; } protected boolean CheckStoragePoolStatus(StoragePoolStatus status) { boolean returnValue = false; if (getStoragePool() != null) { storage_pool storagePool = DbFacade.getInstance().getStoragePoolDAO().get(getStoragePool().getId()); returnValue = (storagePool.getstatus() == status); if (!returnValue && !getReturnValue().getCanDoActionMessages().contains( VdcBllMessages.ACTION_TYPE_FAILED_STORAGE_POOL_STATUS_ILLEGAL.toString())) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_STORAGE_POOL_STATUS_ILLEGAL); } } return returnValue; } protected boolean CheckStoragePoolStatusNotEqual(StoragePoolStatus status, VdcBllMessages onFailMessage) { boolean returnValue = false; if (getStoragePool() != null) { storage_pool storagePool = DbFacade.getInstance().getStoragePoolDAO().get(getStoragePool().getId()); returnValue = (storagePool.getstatus() != status); if (!returnValue && !getReturnValue().getCanDoActionMessages().contains(onFailMessage.name())) { addCanDoActionMessage(onFailMessage); } } return returnValue; } protected boolean isStorageDomainTypeCorrect(storage_domains storageDomain) { if (storageDomain.getstorage_domain_type() != StorageDomainType.ISO && storageDomain.getstorage_domain_type() != StorageDomainType.ImportExport && getStoragePool().getstorage_pool_type() != storageDomain.getstorage_type()) { addCanDoActionMessage(VdcBllMessages.ERROR_CANNOT_ATTACH_STORAGE_DOMAIN_STORAGE_TYPE_NOT_MATCH); return false; } return true; } protected boolean isStorageDomainNotInPool(storage_domains storageDomain) { boolean returnValue = false; if (storageDomain != null) { // check if there is no pool-domain map returnValue = DbFacade.getInstance() .getStoragePoolIsoMapDAO() .getAllForStorage(storageDomain.getid()) .size() == 0; if (!returnValue) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_STORAGE_DOMAIN_STATUS_ILLEGAL); } } return returnValue; } protected boolean checkDomainCanBeAttached(storage_domains storageDomain) { return checkStorageDomainType(storageDomain) && isStorageDomainFormatCorrectForPool(storageDomain, getStoragePool()) && checkStorageDomainSharedStatusNotLocked(storageDomain) && ((storageDomain.getstorage_domain_type() == StorageDomainType.ISO || storageDomain.getstorage_domain_type() == StorageDomainType.ImportExport) || isStorageDomainNotInPool(storageDomain)) && isStorageDomainTypeCorrect(storageDomain); } /** * Check that we are not trying to attach more than one ISO or export * domain to the same data center. */ protected boolean checkStorageDomainType(final storage_domains storageDomain) { // Nothing to check if the storage domain is not an ISO or export: final StorageDomainType type = storageDomain.getstorage_domain_type(); if (type != StorageDomainType.ISO && type != StorageDomainType.ImportExport) { return true; } // Get the number of storage domains of the given type currently attached // to the pool: int count = LinqUtils.filter( DbFacade.getInstance().getStorageDomainDAO().getAllForStoragePool(getStoragePool().getId()), new Predicate<storage_domains>() { @Override public boolean eval(storage_domains a) { return a.getstorage_domain_type() == type; } } ).size(); // If the count is zero we are okay, we can add a new one: if (count == 0) { return true; } // If we are here then we already have at least one storage type of the given type // so whe have to prepare a friendy message for the user (see #713160) and fail: if (type == StorageDomainType.ISO) { addCanDoActionMessage(VdcBllMessages.ERROR_CANNOT_ATTACH_MORE_THAN_ONE_ISO_DOMAIN); } else if (type == StorageDomainType.ImportExport) { addCanDoActionMessage(VdcBllMessages.ERROR_CANNOT_ATTACH_MORE_THAN_ONE_EXPORT_DOMAIN); } return false; } protected boolean checkStorageDomainSharedStatusNotLocked(storage_domains storageDomain) { boolean returnValue = storageDomain != null && storageDomain.getstorage_domain_shared_status() != StorageDomainSharedStatus.Locked; if (!returnValue) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_STORAGE_DOMAIN_STATUS_ILLEGAL); } return returnValue; } protected boolean isStorageDomainNotNull(storage_domains domain) { if (domain == null) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_STORAGE_DOMAIN_NOT_EXIST); return false; } return true; } protected void CalcStoragePoolStatusByDomainsStatus() { List<storage_domains> domains = DbFacade.getInstance().getStorageDomainDAO().getAllForStoragePool( getStoragePool().getId()); // storage_domains masterDomain = null; //LINQ 31899 domains.Where(a => // a.storage_domain_type == StorageDomainType.Master).FirstOrDefault(); storage_domains masterDomain = LinqUtils.firstOrNull(domains, new Predicate<storage_domains>() { @Override public boolean eval(storage_domains a) { return a.getstorage_domain_type() == StorageDomainType.Master; } }); // if no master then Uninitialized // if master not active maintenance StoragePoolStatus newStatus = (masterDomain == null) ? StoragePoolStatus.Uninitialized : (masterDomain.getstatus() != null && masterDomain.getstatus() == StorageDomainStatus.InActive) ? StoragePoolStatus.Maintanance : (masterDomain.getstatus() != null && masterDomain.getstatus() == StorageDomainStatus.Active) ? StoragePoolStatus.Up : StoragePoolStatus.Problematic; if (newStatus != getStoragePool().getstatus()) { getCompensationContext().snapshotEntity(getStoragePool()); getStoragePool().setstatus(newStatus); storage_pool poolFromDb = DbFacade.getInstance().getStoragePoolDAO().get(getStoragePool().getId()); if ((getStoragePool().getspm_vds_id() == null && poolFromDb.getspm_vds_id() != null) || (getStoragePool().getspm_vds_id() != null && !getStoragePool().getspm_vds_id().equals( poolFromDb.getspm_vds_id()))) { getStoragePool().setspm_vds_id(poolFromDb.getspm_vds_id()); } if (getStoragePool().getstatus() == StoragePoolStatus.Uninitialized) { getStoragePool().setspm_vds_id(null); } TransactionSupport.executeInScope(TransactionScopeOption.Required, new TransactionMethod<storage_pool>() { @Override public storage_pool runInTransaction() { DbFacade.getInstance().getStoragePoolDAO().update(getStoragePool()); return null; } }); StoragePoolStatusHandler.PoolStatusChanged(getStoragePool().getId(), getStoragePool().getstatus()); } } protected boolean CheckStoragePoolNameLengthValid() { boolean result = true; if (getStoragePool().getname().length() > Config.<Integer> GetValue(ConfigValues.StoragePoolNameSizeLimit)) { result = false; addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_NAME_LENGTH_IS_TOO_LONG); } return result; } /** * The following method should check if the format of the storage domain allows to it to be attached to the storage * pool. At case of failure the false value will be return and appropriate error message will be added to * canDoActionMessages * @param storageDomain * -the domain object * @param storagePool * - the pool object * @return */ protected boolean isStorageDomainFormatCorrectForPool(storage_domains storageDomain, storage_pool storagePool) { if (storageDomain.getstorage_domain_type() == StorageDomainType.ISO || storageDomain.getstorage_domain_type() == StorageDomainType.ImportExport) { return true; } Set<StorageFormatType> supportedFormatsSet = getSupportedStorageFormatSet(storagePool.getcompatibility_version()); if (supportedFormatsSet.contains(storageDomain.getStorageFormat())) { if (storagePool.getStoragePoolFormatType() == null || storagePool.getStoragePoolFormatType() == storageDomain.getStorageFormat()) { return true; } } addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_STORAGE_DOMAIN_FORMAT_ILLEGAL); getReturnValue().getCanDoActionMessages().add( String.format("$storageFormat %1$s", storageDomain.getStorageFormat().toString())); return false; } protected Set<StorageFormatType> getSupportedStorageFormatSet(Version version) { String[] supportedFormats = Config.<String> GetValue(ConfigValues.SupportedStorageFormats, version.toString()).split("[,]"); Set<StorageFormatType> supportedFormatsSet = new HashSet<StorageFormatType>(); for (String supportedFormat : supportedFormats) { supportedFormatsSet.add(StorageFormatType.forValue(supportedFormat)); } return supportedFormatsSet; } protected void runSynchronizeOperation(ActivateDeactivateSingleAsyncOperationFactory factory, Object... addionalParams) { List<VDS> allRunningVdsInPool = getAllRunningVdssInPool(); ArrayList parameters = InitAsyncOperationParameters(allRunningVdsInPool); if (addionalParams.length > 0) { parameters.addAll(Arrays.asList(addionalParams)); } SyncronizeNumberOfAsyncOperations sync = new SyncronizeNumberOfAsyncOperations(allRunningVdsInPool.size(), parameters, factory); sync.Execute(); } private java.util.ArrayList InitAsyncOperationParameters(List<VDS> allRunningVdsInPool) { java.util.ArrayList parameters = new java.util.ArrayList(); parameters.add(allRunningVdsInPool); parameters.add(getStorageDomain()); parameters.add(getStoragePool()); return parameters; } @Override public Map<Guid, VdcObjectType> getPermissionCheckSubjects() { return Collections.singletonMap(getStoragePoolId() == null ? null : getStoragePoolId().getValue(), VdcObjectType.StoragePool); } }