package org.ovirt.engine.core.bll.storage.connection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.ovirt.engine.core.bll.Backend; import org.ovirt.engine.core.bll.context.CommandContext; import org.ovirt.engine.core.bll.job.ExecutionHandler; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.action.ConnectHostToStoragePoolServersParameters; import org.ovirt.engine.core.common.action.HostStoragePoolParametersBase; import org.ovirt.engine.core.common.action.SetNonOperationalVdsParameters; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.businessentities.NonOperationalReason; import org.ovirt.engine.core.common.businessentities.StorageDomain; import org.ovirt.engine.core.common.businessentities.StorageDomainStatic; import org.ovirt.engine.core.common.businessentities.StorageDomainStatus; import org.ovirt.engine.core.common.businessentities.StorageServerConnections; import org.ovirt.engine.core.common.businessentities.VDS; import org.ovirt.engine.core.common.businessentities.storage.LUNs; import org.ovirt.engine.core.common.businessentities.storage.StorageType; import org.ovirt.engine.core.common.errors.EngineError; import org.ovirt.engine.core.common.errors.EngineFault; import org.ovirt.engine.core.common.utils.Pair; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dal.dbbroker.DbFacade; import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogDirector; import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogable; import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogableImpl; import org.ovirt.engine.core.dao.LunDao; import org.slf4j.Logger; public abstract class StorageHelperBase implements IStorageHelper { protected abstract Pair<Boolean, EngineFault> runConnectionStorageToDomain(StorageDomain storageDomain, Guid vdsId, int type); protected Pair<Boolean, EngineFault> runConnectionStorageToDomain(StorageDomain storageDomain, Guid vdsId, int type, LUNs lun, Guid storagePoolId) { return new Pair<>(true, null); } @Override public boolean connectStorageToDomainByVdsId(StorageDomain storageDomain, Guid vdsId) { return connectStorageToDomainByVdsIdDetails(storageDomain, vdsId).getFirst(); } @Override public Pair<Boolean, EngineFault> connectStorageToDomainByVdsIdDetails(StorageDomain storageDomain, Guid vdsId) { return runConnectionStorageToDomain(storageDomain, vdsId, VdcActionType.ConnectStorageToVds.getValue()); } @Override public boolean disconnectStorageFromDomainByVdsId(StorageDomain storageDomain, Guid vdsId) { return runConnectionStorageToDomain(storageDomain, vdsId, VdcActionType.DisconnectStorageServerConnection.getValue()).getFirst(); } @Override public boolean connectStorageToLunByVdsId(StorageDomain storageDomain, Guid vdsId, LUNs lun, Guid storagePoolId) { return runConnectionStorageToDomain(storageDomain, vdsId, VdcActionType.ConnectStorageToVds.getValue(), lun, storagePoolId).getFirst(); } @Override public boolean disconnectStorageFromLunByVdsId(StorageDomain storageDomain, Guid vdsId, LUNs lun) { return runConnectionStorageToDomain(storageDomain, vdsId, VdcActionType.DisconnectStorageServerConnection.getValue(), lun, Guid.Empty).getFirst(); } @Override public boolean storageDomainRemoved(StorageDomainStatic storageDomain) { return true; } @Override public void removeLun(LUNs lun) { if (lun.getVolumeGroupId().isEmpty()) { DbFacade.getInstance().getLunDao().remove(lun.getLUNId()); for (StorageServerConnections connection : filterConnectionsUsedByOthers(lun.getLunConnections(), "", lun.getLUNId())) { DbFacade.getInstance().getStorageServerConnectionDao().remove(connection.getId()); } } } protected List<StorageServerConnections> filterConnectionsUsedByOthers( List<StorageServerConnections> connections, String vgId, final String lunId) { return Collections.emptyList(); } @Override public boolean isConnectSucceeded(Map<String, String> returnValue, List<StorageServerConnections> connections) { return true; } @Override public boolean prepareConnectHostToStoragePoolServers(CommandContext cmdContext, ConnectHostToStoragePoolServersParameters parameters, List<StorageServerConnections> connections) { return true; } @Override public void prepareDisconnectHostFromStoragePoolServers(HostStoragePoolParametersBase parameters, List<StorageServerConnections> connections) { // default implementation } @Override public Pair<Boolean, AuditLogType> disconnectHostFromStoragePoolServersCommandCompleted(HostStoragePoolParametersBase parameters) { return new Pair<>(true, null); } public static Map<StorageType, List<StorageServerConnections>> filterConnectionsByStorageType(LUNs lun) { return lun.getLunConnections().stream().collect(Collectors.groupingBy(StorageServerConnections::getStorageType)); } protected boolean isActiveStorageDomainAvailable(final StorageType storageType, Guid poolId) { List<StorageDomain> storageDomains = DbFacade.getInstance().getStorageDomainDao().getAllForStoragePool(poolId); return storageDomains.stream() .anyMatch(s -> s.getStorageType() == storageType && s.getStatus() == StorageDomainStatus.Active); } protected void setNonOperational(CommandContext cmdContext, Guid vdsId, NonOperationalReason reason) { Backend.getInstance().runInternalAction(VdcActionType.SetNonOperationalVds, new SetNonOperationalVdsParameters(vdsId, reason), ExecutionHandler.createInternalJobContext(cmdContext)); } protected static LunDao getLunDao() { return DbFacade.getInstance().getLunDao(); } protected int removeStorageDomainLuns(StorageDomainStatic storageDomain) { final List<LUNs> lunsList = getLunDao().getAllForVolumeGroup(storageDomain.getStorage()); int numOfRemovedLuns = 0; for (LUNs lun : lunsList) { if (removeLunFromStorageDomain(lun)) { numOfRemovedLuns++; } } return numOfRemovedLuns; } private boolean removeLunFromStorageDomain(LUNs lun) { if (DbFacade.getInstance().getDiskLunMapDao().getDiskIdByLunId(lun.getLUNId()) == null) { getLunDao().remove(lun.getLUNId()); return true; } lun.setVolumeGroupId(""); getLunDao().update(lun); return false; } @Override public void removeLunFromStorageDomain(String lunId) { removeLunFromStorageDomain(getLunDao().get(lunId)); } protected String addToAuditLogErrorMessage(String connection, String errorCode, List<StorageServerConnections> connections) { return addToAuditLogErrorMessage(connection, errorCode, connections, null); } protected String addToAuditLogErrorMessage(String connection, String errorCode, List<StorageServerConnections> connections, LUNs lun) { AuditLogable logable = new AuditLogableImpl(); String connectionField = getConnectionDescription(connections, connection) + (lun == null ? "" : " (LUN " + lun.getLUNId() + ")"); logable.addCustomValue("Connection", connectionField); // Get translated error by error code ,if no translation found (should not happened) , // will set the error code instead. String translatedError = getTranslatedStorageError(errorCode); logable.addCustomValue("ErrorMessage", translatedError); new AuditLogDirector().log(logable, AuditLogType.STORAGE_DOMAIN_ERROR); return connectionField; } protected void printLog(Logger logger, String connectionField, String errorCode) { String translatedError = getTranslatedStorageError(errorCode); logger.error( "The connection with details '{}' failed because of error code '{}' and error message is: {}", connectionField, errorCode, Backend.getInstance().getVdsErrorsTranslator() .translateErrorTextSingle(translatedError)); } /** * Get translated error by error code ,if no enum for the error code (should not happened) , will set the error code * instead. <BR/> * When no enum found for the error code, we should check it with the vdsm team. * * @param errorCode * - The error code we want to translate. * @return - Translated error if found or error code. */ private String getTranslatedStorageError(String errorCode) { String translatedError = errorCode; EngineError error = EngineError.forValue(Integer.parseInt(errorCode)); if (error != null) { translatedError = Backend.getInstance() .getVdsErrorsTranslator() .translateErrorTextSingle(error.toString()); } return translatedError; } private String getConnectionDescription(List<StorageServerConnections> connections, String connectionId) { // Using Guid in order to handle nulls. This can happened when we trying // to import an existing domain Guid connectionIdGuid = Guid.createGuidFromStringDefaultEmpty(connectionId); for (StorageServerConnections connection : connections) { Guid connectionGuid = Guid.createGuidFromStringDefaultEmpty(connection.getId()); if (connectionGuid.equals(connectionIdGuid)) { String desc = connection.getConnection(); if (connection.getIqn() != null) { desc += " " + connection.getIqn(); } return desc; } } return ""; } @Override public boolean syncDomainInfo(StorageDomain storageDomain, Guid vdsId) { return true; } public static void addMessageToAuditLog(AuditLogType auditLogType, StorageDomain storageDomain, VDS vds){ AuditLogable logable = new AuditLogableImpl(); logable.setVdsId(vds.getId()); logable.setVdsName(vds.getName()); if (storageDomain != null) { logable.setStorageDomainId(storageDomain.getId()); logable.setStorageDomainName(storageDomain.getName()); } new AuditLogDirector().log(logable, auditLogType); } }