package org.ovirt.engine.core.bll.storage.domain; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.Collectors; 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.storage.connection.CINDERStorageHelper; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.action.DetachStorageDomainFromPoolParameters; import org.ovirt.engine.core.common.action.LockProperties; 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.VM; import org.ovirt.engine.core.common.businessentities.VmStatic; 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.common.vdscommands.DetachStorageDomainVDSCommandParameters; 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.compat.Guid; import org.ovirt.engine.core.dao.StoragePoolIsoMapDao; import org.ovirt.engine.core.dao.VmDao; import org.ovirt.engine.core.dao.VmStaticDao; import org.ovirt.engine.core.dao.profiles.DiskProfileDao; import org.ovirt.engine.core.utils.transaction.TransactionSupport; @NonTransactiveCommandAttribute(forceCompensation=true) public class DetachStorageDomainFromPoolCommand<T extends DetachStorageDomainFromPoolParameters> extends StorageDomainCommandBase<T> { @Inject private DiskProfileDao diskProfileDao; @Inject private VmStaticDao vmStaticDao; @Inject private StoragePoolIsoMapDao storagePoolIsoMapDao; @Inject private VmDao vmDao; public DetachStorageDomainFromPoolCommand(T parameters, CommandContext commandContext) { super(parameters, commandContext); } @Override protected LockProperties applyLockProperties(LockProperties lockProperties) { return lockProperties.withScope(LockProperties.Scope.Command); } @Override protected Map<String, Pair<String, String>> getExclusiveLocks() { return Collections.singletonMap(getParameters().getStorageDomainId().toString(), LockMessagesMatchUtil.makeLockingPair(LockingGroup.STORAGE, EngineMessage.ACTION_TYPE_FAILED_OBJECT_LOCKED)); } /** * Constructor for command creation when compensation is applied on startup */ public DetachStorageDomainFromPoolCommand(Guid commandId) { super(commandId); } @Override protected void executeCommand() { if (getStorageDomain().getStorageType().isCinderDomain()) { detachCinderStorageDomain(); return; } log.info("Start detach storage domain"); changeStorageDomainStatusInTransaction(getStorageDomain().getStoragePoolIsoMapData(), StorageDomainStatus.Detaching); log.info(" Detach storage domain: before connect"); connectHostsInUpToDomainStorageServer(); log.info(" Detach storage domain: after connect"); VDSReturnValue returnValue = runVdsCommand( VDSCommandType.DetachStorageDomain, new DetachStorageDomainVDSCommandParameters(getParameters().getStoragePoolId(), getParameters().getStorageDomainId(), Guid.Empty, getStoragePool() .getMasterDomainVersion())); log.info(" Detach storage domain: after disconnect storage"); TransactionSupport.executeInNewTransaction(() -> { releaseStorageDomainMacPool(getVmsOnlyOnStorageDomain()); detachStorageDomainWithEntities(getStorageDomain()); StoragePoolIsoMap mapToRemove = getStorageDomain().getStoragePoolIsoMapData(); getCompensationContext().snapshotEntity(mapToRemove); storagePoolIsoMapDao.remove(new StoragePoolIsoMapId(mapToRemove.getStorageId(), mapToRemove.getStoragePoolId())); // when detaching SD for data center, we should remove any attachment to qos, which is part of the old // data center diskProfileDao.nullifyQosForStorageDomain(getStorageDomain().getId()); getCompensationContext().stateChanged(); return null; }); log.info(" Detach storage domain: after detach in vds"); disconnectAllHostsInPool(); if (returnValue.getSucceeded() && getStorageDomain().getStorageDomainType() == StorageDomainType.ISO) { // reset iso for this pool in vdsBroker cache runVdsCommand(VDSCommandType.ResetISOPath, new IrsBaseVDSCommandParameters(getParameters().getStoragePoolId())); } log.info("End detach storage domain"); setSucceeded(returnValue.getSucceeded()); } private List<VM> getVmsOnlyOnStorageDomain() { List<VM> allVmsRelatedToSD = vmDao.getAllForStorageDomain(getStorageDomainId()); List<VM> vmsWithDisksOnMultipleStorageDomain = vmDao.getAllVMsWithDisksOnOtherStorageDomain(getStorageDomainId()); allVmsRelatedToSD.removeAll(vmsWithDisksOnMultipleStorageDomain); return allVmsRelatedToSD; } private void detachCinderStorageDomain() { CINDERStorageHelper CINDERStorageHelper = new CINDERStorageHelper(); CINDERStorageHelper.detachCinderDomainFromPool(getStorageDomain().getStoragePoolIsoMapData()); setSucceeded(true); } @Override public AuditLogType getAuditLogTypeValue() { return getSucceeded() ? AuditLogType.USER_DETACH_STORAGE_DOMAIN_FROM_POOL : AuditLogType.USER_DETACH_STORAGE_DOMAIN_FROM_POOL_FAILED; } @Override protected boolean validate() { return canDetachStorageDomainWithVmsAndDisks(getStorageDomain()) && canDetachDomain(getParameters().getDestroyingPool(), getParameters().getRemoveLast()) && isNoLeasesOnStorageDomain(); } private boolean isNoLeasesOnStorageDomain() { List<VmStatic> entitiesWithLeases = vmStaticDao.getAllWithLeaseOnStorageDomain(getStorageDomain().getId()); if (!entitiesWithLeases.isEmpty()) { String names = entitiesWithLeases.stream().map(VmStatic::getName).collect(Collectors.joining(", ")); return failValidation(EngineMessage.ERROR_CANNOT_DETACH_DOMAIN_WITH_VMS_AND_TEMPLATES_LEASES, String.format("$entitiesNames %s", names)); } return true; } @Override protected void setActionMessageParameters() { addValidationMessage(EngineMessage.VAR__TYPE__STORAGE__DOMAIN); addValidationMessage(EngineMessage.VAR__ACTION__DETACH); } }