package org.ovirt.engine.core.bll.storage.domain; import static org.ovirt.engine.core.common.businessentities.NonOperationalReason.STORAGE_DOMAIN_UNREACHABLE; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; import javax.inject.Inject; 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.bll.job.ExecutionHandler; import org.ovirt.engine.core.bll.storage.connection.CINDERStorageHelper; import org.ovirt.engine.core.bll.storage.connection.StorageHelperDirector; import org.ovirt.engine.core.bll.storage.pool.RefreshPoolSingleAsyncOperationFactory; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.action.LockProperties; import org.ovirt.engine.core.common.action.LockProperties.Scope; import org.ovirt.engine.core.common.action.SetNonOperationalVdsParameters; import org.ovirt.engine.core.common.action.StorageDomainPoolParametersBase; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.businessentities.StorageDomainStatus; import org.ovirt.engine.core.common.businessentities.StorageDomainType; import org.ovirt.engine.core.common.businessentities.StoragePoolIsoMap; import org.ovirt.engine.core.common.businessentities.StoragePoolIsoMapId; import org.ovirt.engine.core.common.businessentities.StoragePoolStatus; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.common.eventqueue.Event; import org.ovirt.engine.core.common.eventqueue.EventType; import org.ovirt.engine.core.common.locks.LockingGroup; import org.ovirt.engine.core.common.utils.Pair; import org.ovirt.engine.core.common.vdscommands.ActivateStorageDomainVDSCommandParameters; import org.ovirt.engine.core.common.vdscommands.VDSCommandType; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.compat.TransactionScopeOption; import org.ovirt.engine.core.dao.StoragePoolIsoMapDao; import org.ovirt.engine.core.utils.transaction.TransactionSupport; @NonTransactiveCommandAttribute(forceCompensation = true) public class ActivateStorageDomainCommand<T extends StorageDomainPoolParametersBase> extends StorageDomainCommandBase<T> { @Inject private IsoDomainListSynchronizer isoDomainListSynchronizer; @Inject private StoragePoolIsoMapDao storagePoolIsoMapDao; public ActivateStorageDomainCommand(T parameters, CommandContext commandContext) { super(parameters, commandContext); } @Override protected LockProperties applyLockProperties(LockProperties lockProperties) { return lockProperties.withScope(Scope.Execution); } /** * Constructor for command creation when compensation is applied on startup */ public ActivateStorageDomainCommand(Guid commandId) { super(commandId); } @Override protected boolean validate() { boolean returnValue = checkStoragePool() && checkStoragePoolStatusNotEqual(StoragePoolStatus.Uninitialized, EngineMessage.ACTION_TYPE_FAILED_STORAGE_POOL_STATUS_ILLEGAL) && checkStorageDomain() && storageDomainStatusIsValid() && (getStorageDomain().getStorageDomainType() == StorageDomainType.Master || checkMasterDomainIsUp()) && checkForActiveVds() != null; return returnValue; } private void syncStorageDomainInfo(List<Pair<Guid, Boolean>> hostConnectionInfo) { for (Pair<Guid, Boolean> pair : hostConnectionInfo) { if (Boolean.TRUE.equals(pair.getSecond())) { if (StorageHelperDirector.getInstance() .getItem(getStorageDomain().getStorageType()) .syncDomainInfo(getStorageDomain(), pair.getFirst())) { break; } } } } @Override protected void executeCommand() { if (isCinderStorageDomain()) { activateCinderStorageDomain(); return; } final StoragePoolIsoMap map = storagePoolIsoMapDao .get(new StoragePoolIsoMapId(getParameters().getStorageDomainId(), getParameters().getStoragePoolId())); // Master domain must not go through the Activating status. changeStorageDomainStatusInTransaction(map, (getStorageDomain().getStorageDomainType() == StorageDomainType.Master) ? StorageDomainStatus.Locked : StorageDomainStatus.Activating); freeLock(); log.info("ActivateStorage Domain. Before Connect all hosts to pool. Time: {}", new Date()); List<Pair<Guid, Boolean>> hostsConnectionResults = connectHostsInUpToDomainStorageServer(); if (isAllHostConnectionFailed(hostsConnectionResults)) { log.error("Cannot connect storage server, aborting Storage Domain activation."); setSucceeded(false); return; } syncStorageDomainInfo(hostsConnectionResults); runVdsCommand(VDSCommandType.ActivateStorageDomain, new ActivateStorageDomainVDSCommandParameters(getStoragePool().getId(), getStorageDomain().getId())); log.info("ActivateStorage Domain. After Connect all hosts to pool. Time: {}", new Date()); TransactionSupport.executeInNewTransaction(() -> { map.setStatus(StorageDomainStatus.Active); storagePoolIsoMapDao.updateStatus(map.getId(), map.getStatus()); if (getStorageDomain().getStorageDomainType() == StorageDomainType.Master) { calcStoragePoolStatusByDomainsStatus(); } return null; }); refreshAllVdssInPool(); log.info("ActivateStorage Domain. After change storage pool status in vds. Time: {}", new Date()); if (getStorageDomain().getStorageDomainType() == StorageDomainType.ISO) { isoDomainListSynchronizer.refresheIsoDomainWhenActivateDomain(getStorageDomain().getId(), getStoragePool().getId()); } setSucceeded(true); } private boolean isAllHostConnectionFailed(List<Pair<Guid, Boolean>> hostsConnectionResults) { return hostsConnectionResults.stream().map(Pair::getSecond).noneMatch(Boolean.TRUE::equals); } private void activateCinderStorageDomain() { List<Pair<Guid, Boolean>> hostsConnectionResults = connectHostsInUpToDomainStorageServer(); for (Pair<Guid, Boolean> pair : hostsConnectionResults) { if (!pair.getSecond()) { log.error("Failed to activate Cinder storage domain '{}' due to secrets registration failure.", getStorageDomain().getName()); return; } } CINDERStorageHelper CINDERStorageHelper = new CINDERStorageHelper(); CINDERStorageHelper.activateCinderDomain(getParameters().getStorageDomainId(), getParameters().getStoragePoolId()); setSucceeded(true); } private void refreshAllVdssInPool() { final List<Guid> vdsIdsToSetNonOperational = new ArrayList<>(); getEventQueue().submitEventSync( new Event(getParameters().getStoragePoolId(), getParameters().getStorageDomainId(), null, EventType.POOLREFRESH, ""), () -> { runSynchronizeOperation(new RefreshPoolSingleAsyncOperationFactory(), vdsIdsToSetNonOperational); return null; } ); for (Guid vdsId : vdsIdsToSetNonOperational) { Map<String, String> customLogValues = Collections.singletonMap("StorageDomainNames", getStorageDomainName()); SetNonOperationalVdsParameters tempVar = new SetNonOperationalVdsParameters(vdsId, STORAGE_DOMAIN_UNREACHABLE, customLogValues); tempVar.setStorageDomainId(getStorageDomain().getId()); tempVar.setTransactionScopeOption(TransactionScopeOption.RequiresNew); runInternalAction(VdcActionType.SetNonOperationalVds, tempVar, ExecutionHandler.createInternalJobContext(getContext())); } } @Override public AuditLogType getAuditLogTypeValue() { if (getParameters().isRunSilent()) { return getSucceeded() ? AuditLogType.USER_ACTIVATED_STORAGE_DOMAIN_ASYNC : AuditLogType.USER_ACTIVATE_STORAGE_DOMAIN_FAILED_ASYNC; } return getSucceeded() ? AuditLogType.USER_ACTIVATED_STORAGE_DOMAIN : AuditLogType.USER_ACTIVATE_STORAGE_DOMAIN_FAILED; } @Override protected Map<String, Pair<String, String>> getExclusiveLocks() { return Collections.singletonMap(getStorageDomainId().toString(), LockMessagesMatchUtil.makeLockingPair(LockingGroup.STORAGE, EngineMessage.ACTION_TYPE_FAILED_OBJECT_LOCKED)); } @Override protected void setActionMessageParameters() { addValidationMessage(EngineMessage.VAR__TYPE__STORAGE__DOMAIN); addValidationMessage(EngineMessage.VAR__ACTION__ACTIVATE); } private boolean storageDomainStatusIsValid() { boolean returnValue; if (isInternalExecution()) { returnValue = checkStorageDomainStatus(StorageDomainStatus.Inactive, StorageDomainStatus.Unknown, StorageDomainStatus.Locked, StorageDomainStatus.Maintenance, StorageDomainStatus.PreparingForMaintenance); } else { returnValue = checkStorageDomainStatus(StorageDomainStatus.Inactive, StorageDomainStatus.Unknown, StorageDomainStatus.Maintenance, StorageDomainStatus.PreparingForMaintenance); } return returnValue; } }