package org.ovirt.engine.core.bll.storage.connection; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.inject.Inject; import org.apache.commons.lang.StringUtils; import org.ovirt.engine.core.bll.LockMessagesMatchUtil; import org.ovirt.engine.core.bll.NonTransactiveCommandAttribute; import org.ovirt.engine.core.bll.context.CommandContext; import org.ovirt.engine.core.common.action.LockProperties; import org.ovirt.engine.core.common.action.LockProperties.Scope; import org.ovirt.engine.core.common.action.StorageServerConnectionParametersBase; import org.ovirt.engine.core.common.businessentities.StorageDomain; import org.ovirt.engine.core.common.businessentities.StorageServerConnections; 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.EngineMessage; import org.ovirt.engine.core.common.locks.LockingGroup; import org.ovirt.engine.core.common.utils.Pair; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dao.LunDao; import org.ovirt.engine.core.dao.StorageServerConnectionDao; @NonTransactiveCommandAttribute public class RemoveStorageServerConnectionCommand<T extends StorageServerConnectionParametersBase> extends DisconnectStorageServerConnectionCommand<T> { @Inject private StorageServerConnectionDao storageServerConnectionDao; @Inject private LunDao lunDao; public RemoveStorageServerConnectionCommand(T parameters, CommandContext cmdContext) { super(parameters, cmdContext); } @Override protected LockProperties applyLockProperties(LockProperties lockProperties) { return lockProperties.withScope(Scope.Execution); } @Override protected boolean validate() { String connectionId = getConnection().getId(); List<StorageDomain> domains = null; if (StringUtils.isEmpty(connectionId) ) { return failValidation(EngineMessage.ACTION_TYPE_FAILED_STORAGE_CONNECTION_ID_EMPTY); } StorageServerConnections connection = storageServerConnectionDao.get(connectionId); if(connection == null) { return failValidation(EngineMessage.ACTION_TYPE_FAILED_STORAGE_CONNECTION_NOT_EXIST); } // if user passed only the connection id for removal, vdsm still needs few more details in order to disconnect, so // bringing them from db and repopulating them in the connection object received in input parameters populateMissingFields(connection); StorageType storageType = connection.getStorageType(); if (storageType.isFileDomain()) { // go to storage domain static, get all storage domains where storage field = storage connection id domains = getStorageDomainsByConnId(connectionId); if(domains.size() > 0) { String domainNames = createDomainNamesListFromStorageDomains(domains); return prepareFailureMessageForDomains(domainNames); } } else if (storageType.equals(StorageType.ISCSI)) { List<String> domainNames = new ArrayList<>(); List<String> diskNames = new ArrayList<>(); // go to luns to storage connections map table, get it from there List<LUNs> luns = lunDao.getAllForStorageServerConnection(connectionId); if (!luns.isEmpty()) { String volumeGroupId = null; for(LUNs lun : luns) { volumeGroupId = lun.getVolumeGroupId(); if (StringUtils.isNotEmpty(volumeGroupId)) { // non empty vg id indicates there's a storage domain using the lun String domainName = lun.getStorageDomainName(); domainNames.add(domainName); } else { // empty vg id indicates there's a lun disk using the lun String lunDiskName = lun.getDiskAlias(); diskNames.add(lunDiskName); } } String domainNamesForMessage = null; if (!domainNames.isEmpty() ) { // Build domain names list to display in the error domainNamesForMessage = prepareEntityNamesForMessage(domainNames); if (diskNames.isEmpty()) { return prepareFailureMessageForDomains(domainNamesForMessage); } else { String diskNamesForMessage = prepareEntityNamesForMessage(diskNames); return prepareFailureMessageForDomainsAndDisks(domainNamesForMessage, diskNamesForMessage); } } else if (!diskNames.isEmpty()) { String diskNamesForMessage = prepareEntityNamesForMessage(diskNames); return prepareFailureMessageForDisks(diskNamesForMessage); } } } return true; } private String prepareEntityNamesForMessage(List<String> entityNames) { return StringUtils.join(entityNames, ","); } @Override protected void executeCommand() { String connectionId = getConnection().getId(); storageServerConnectionDao.remove(connectionId); log.info("Removing connection '{}' from database ", connectionId); if (Guid.isNullOrEmpty(getParameters().getVdsId())) { log.info("No vdsId passed - hosts will not be disconnected."); } else { // disconnect the connection from vdsm disconnectStorage(); } setSucceeded(true); } protected void populateMissingFields(StorageServerConnections connectionFromDb) { StorageServerConnections connectionFromParams = getConnection(); if(connectionFromParams.getStorageType() == null || connectionFromParams.getStorageType().equals(StorageType.UNKNOWN)) { connectionFromParams.setStorageType(connectionFromDb.getStorageType()); } if(StringUtils.isEmpty(connectionFromParams.getConnection())) { connectionFromParams.setConnection(connectionFromDb.getConnection()); } if(connectionFromParams.getStorageType().equals(StorageType.ISCSI)){ if(StringUtils.isEmpty(connectionFromParams.getIqn())) { connectionFromParams.setIqn(connectionFromDb.getIqn()); } if(StringUtils.isEmpty(connectionFromParams.getUserName())) { connectionFromParams.setUserName(connectionFromDb.getUserName()); } if(StringUtils.isEmpty(connectionFromParams.getPassword())) { connectionFromParams.setPassword(connectionFromDb.getPassword()); } if(StringUtils.isEmpty(connectionFromParams.getPort())) { connectionFromParams.setPort(connectionFromDb.getPort()); } } } protected boolean prepareFailureMessageForDomains(String domainNames) { addValidationMessageVariable("domainNames", domainNames); return failValidation(EngineMessage.ACTION_TYPE_FAILED_STORAGE_CONNECTION_BELONGS_TO_SEVERAL_STORAGE_DOMAINS); } protected boolean prepareFailureMessageForDisks(String diskNames) { addValidationMessageVariable("diskNames", diskNames); return failValidation(EngineMessage.ACTION_TYPE_FAILED_STORAGE_CONNECTION_BELONGS_TO_SEVERAL_DISKS); } protected boolean prepareFailureMessageForDomainsAndDisks(String domainNames, String diskNames) { addValidationMessageVariable("domainNames", domainNames); addValidationMessageVariable("diskNames", diskNames); return failValidation(EngineMessage.ACTION_TYPE_FAILED_STORAGE_CONNECTION_BELONGS_TO_SEVERAL_STORAGE_DOMAINS_AND_DISKS); } protected String createDomainNamesListFromStorageDomains(List<StorageDomain> domains) { // Build domain names list to display in the error StringBuilder domainNames = new StringBuilder(); for (StorageDomain domain : domains) { domainNames.append(domain.getStorageName()); domainNames.append(","); } // Remove the last "," after the last domain domainNames.deleteCharAt(domainNames.length() - 1); return domainNames.toString(); } @Override protected Map<String, Pair<String, String>> getExclusiveLocks() { Map<String, Pair<String, String>> locks = new HashMap<>(); locks.put(getConnection().getConnection(), LockMessagesMatchUtil.makeLockingPair(LockingGroup.STORAGE_CONNECTION, EngineMessage.ACTION_TYPE_FAILED_OBJECT_LOCKED)); // lock connection's id to avoid editing or removing this connection at the same time // by another user locks.put(getConnection().getId(), LockMessagesMatchUtil.makeLockingPair(LockingGroup.STORAGE_CONNECTION, EngineMessage.ACTION_TYPE_FAILED_OBJECT_LOCKED)); return locks; } @Override protected void setActionMessageParameters() { addValidationMessage(EngineMessage.VAR__ACTION__REMOVE); addValidationMessage(EngineMessage.VAR__TYPE__STORAGE__CONNECTION); } }