package org.ovirt.engine.core.bll.storage;
import java.text.MessageFormat;
import java.util.List;
import org.ovirt.engine.core.bll.Backend;
import org.ovirt.engine.core.bll.NonTransactiveCommandAttribute;
import org.ovirt.engine.core.bll.VmCommand;
import org.ovirt.engine.core.common.AuditLogType;
import org.ovirt.engine.core.common.action.ReconstructMasterParameters;
import org.ovirt.engine.core.common.businessentities.StorageDomainStatus;
import org.ovirt.engine.core.common.businessentities.VDS;
import org.ovirt.engine.core.common.businessentities.VDSStatus;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.storage_pool_iso_map;
import org.ovirt.engine.core.common.errors.VdcBLLException;
import org.ovirt.engine.core.common.errors.VdcBllErrors;
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.common.vdscommands.ConnectStoragePoolVDSCommandParameters;
import org.ovirt.engine.core.common.vdscommands.DisconnectStoragePoolVDSCommandParameters;
import org.ovirt.engine.core.common.vdscommands.MarkPoolInReconstructModeVDSCommandParameters;
import org.ovirt.engine.core.common.vdscommands.ReconstructMarkAction;
import org.ovirt.engine.core.common.vdscommands.ReconstructMasterVDSCommandParameters;
import org.ovirt.engine.core.common.vdscommands.RefreshStoragePoolVDSCommandParameters;
import org.ovirt.engine.core.common.vdscommands.ResetIrsVDSCommandParameters;
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.compat.LogCompat;
import org.ovirt.engine.core.compat.LogFactoryCompat;
import org.ovirt.engine.core.compat.TransactionScopeOption;
import org.ovirt.engine.core.dal.VdcBllMessages;
import org.ovirt.engine.core.dal.dbbroker.DbFacade;
import org.ovirt.engine.core.utils.transaction.TransactionMethod;
import org.ovirt.engine.core.utils.transaction.TransactionSupport;
@NonTransactiveCommandAttribute(forceCompensation = true)
public class ReconstructMasterDomainCommand<T extends ReconstructMasterParameters> extends
DeactivateStorageDomainCommand<T> {
/**
* Constructor for command creation when compensation is applied on startup
*
* @param commandId
*/
protected ReconstructMasterDomainCommand(Guid commandId) {
super(commandId);
}
public ReconstructMasterDomainCommand(T parameters) {
super(parameters);
}
@Override
protected boolean canDoAction() {
addCanDoActionMessage(VdcBllMessages.VAR__ACTION__RECONSTRUCT_MASTER);
addCanDoActionMessage(VdcBllMessages.VAR__TYPE__STORAGE__DOMAIN);
List<storage_pool_iso_map> poolDomains = DbFacade.getInstance()
.getStoragePoolIsoMapDAO().getAllForStoragePool(getStoragePool().getId());
for (storage_pool_iso_map poolDomain : poolDomains) {
if (poolDomain.getstatus() == StorageDomainStatus.Locked) {
addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_STORAGE_DOMAIN_STATUS_ILLEGAL2);
return false;
}
}
return InitializeVds();
}
@Override
protected void executeCommand() {
try {
boolean commandSucceeded = (Boolean) TransactionSupport.executeInScope(TransactionScopeOption.RequiresNew,
new TransactionMethod<Object>() {
@Override
public Object runInTransaction() {
boolean commandSucceeded = false;
ProceedStorageDomainTreatmentByDomainType(true);
// set status to inactive in order to send it on
// reconstruct or if its last master
if (getParameters().getIsDeactivate()) {
SetStorageDomainStatus(StorageDomainStatus.InActive);
CalcStoragePoolStatusByDomainsStatus();
}
commandSucceeded = true;
if (!_isLastMaster) {
// pause the timers for the domain error handling.
Backend.getInstance()
.getResourceManager()
.RunVdsCommand(
VDSCommandType.MarkPoolInReconstructMode,
new MarkPoolInReconstructModeVDSCommandParameters(getStoragePoolId()
.getValue(), ReconstructMarkAction.ClearJobs));
// if we have spm, stop spm and reset cache (resetIrs)
commandSucceeded = stopSpm();
commandSucceeded =
commandSucceeded
&& Backend
.getInstance()
.getResourceManager()
.RunVdsCommand(
VDSCommandType.DisconnectStoragePool,
new DisconnectStoragePoolVDSCommandParameters(getVds()
.getvds_id(),
getStoragePool().getId(),
getVds().getvds_spm_id()))
.getSucceeded();
if (commandSucceeded) {
List<storage_pool_iso_map> domains = DbFacade.getInstance()
.getStoragePoolIsoMapDAO()
.getAllForStoragePool(getStoragePool().getId());
for (storage_pool_iso_map domain : domains) {
if (domain.getstatus() == null
|| domain.getstatus() == StorageDomainStatus.Unknown) {
domain.setstatus(StorageDomainStatus.Active);
} else if (domain.getstatus() == StorageDomainStatus.Locked) {
throw new VdcBLLException(
VdcBllErrors.CANT_RECONSTRUCT_WHEN_A_DOMAIN_IN_POOL_IS_LOCKED,
"Cannot reconstruct master domain when a domain in the pool is " +
"locked.");
}
}
commandSucceeded = Backend
.getInstance()
.getResourceManager()
.RunVdsCommand(
VDSCommandType.ReconstructMaster,
new ReconstructMasterVDSCommandParameters(getVds().getvds_id(),
getStoragePool().getId(), getStoragePool().getname(),
_newMasterStorageDomainId, domains, getStoragePool()
.getmaster_domain_version())).getSucceeded();
}
} else {
stopSpm();
}
return commandSucceeded;
}
});
connectAndRefreshAllUpHosts(commandSucceeded);
if (!_isLastMaster && commandSucceeded) {
SearchParameters p =
new SearchParameters(MessageFormat.format(DesktopsInStoragePoolQuery, getStoragePool()
.getname()), SearchType.VM);
p.setMaxCount(Integer.MAX_VALUE);
@SuppressWarnings("unchecked")
List<VM> vmsInPool = (List<VM>) Backend.getInstance().runInternalQuery(VdcQueryType.Search, p)
.getReturnValue();
VmCommand.UpdateVmInSpm(getStoragePool().getId(), vmsInPool);
}
setSucceeded(commandSucceeded);
} finally {
// reset cache and mark reconstruct for pool as finished
Backend.getInstance()
.getResourceManager()
.RunVdsCommand(
VDSCommandType.MarkPoolInReconstructMode,
new MarkPoolInReconstructModeVDSCommandParameters(getStoragePoolId()
.getValue(), ReconstructMarkAction.ClearCache));
}
}
protected boolean stopSpm() {
boolean commandSucceeded = true;
if (getStoragePool().getspm_vds_id() != null) {
// if spm host id is different from selected host get the spm
// in order to try and perform stop spm
VDS spm = null;
if (getStoragePool().getspm_vds_id().equals(getVds().getvds_id())) {
spm = getVds();
} else {
spm = DbFacade.getInstance()
.getVdsDAO()
.get(getStoragePool().getspm_vds_id());
}
if (spm != null) {
ResetIrsVDSCommandParameters tempVar2 = new ResetIrsVDSCommandParameters(
getStoragePool().getId(), spm.gethost_name(), spm.getvds_id());
tempVar2.setIgnoreStopFailed(true);
commandSucceeded = Backend.getInstance().getResourceManager()
.RunVdsCommand(VDSCommandType.ResetIrs, tempVar2).getSucceeded();
// if spm host is up switch to use it in the following logic
if (spm.getstatus() == VDSStatus.Up) {
setVdsId(spm.getvds_id());
setVds(spm);
}
}
}
return commandSucceeded;
}
private void connectAndRefreshAllUpHosts(final boolean commandSucceeded) {
TransactionSupport.executeInScope(TransactionScopeOption.RequiresNew,
new TransactionMethod<Object>() {
@Override
public Object runInTransaction() {
try {
for (VDS vds : getAllRunningVdssInPool()) {
try {
if (!_isLastMaster && commandSucceeded) {
VDSReturnValue returnValue = Backend.getInstance()
.getResourceManager()
.RunVdsCommand(
VDSCommandType.ConnectStoragePool,
new ConnectStoragePoolVDSCommandParameters(vds.getvds_id(),
getStoragePool().getId(), vds.getvds_spm_id(),
getMasterDomainIdFromDb(), getStoragePool()
.getmaster_domain_version()));
if (returnValue.getSucceeded()) {
Backend.getInstance()
.getResourceManager()
.RunVdsCommand(
VDSCommandType.RefreshStoragePool,
new RefreshStoragePoolVDSCommandParameters(vds.getvds_id(),
getStoragePool().getId(),
_newMasterStorageDomainId,
getStoragePool().getmaster_domain_version()));
} else {
log.errorFormat("Post reconstruct actions (connectPool) did not complete on host {0} in the pool. error {1}",
vds.getvds_id(),
returnValue.getVdsError().getMessage());
}
}
// only if we deactivate the storage domain we want to disconnect from it.
if (getParameters().getIsDeactivate()) {
StorageHelperDirector.getInstance()
.getItem(getStorageDomain().getstorage_type())
.DisconnectStorageFromDomainByVdsId(getStorageDomain(), vds.getvds_id());
}
} catch (Exception e) {
log.errorFormat("Post reconstruct actions (connectPool,refreshPool,disconnect storage)"
+ " did not complete on host {0} in the pool. error {1}",
vds.getvds_id(),
e.getMessage());
}
}
} catch (Exception ex) {
log.errorFormat("Post reconstruct actions (connectPool,refreshPool,disconnect storage)"
+ " did not complete on all up hosts in the pool. error {0}",
ex.getMessage());
}
return null;
}
});
}
@Override
public AuditLogType getAuditLogTypeValue() {
return getSucceeded() ? _isLastMaster ? AuditLogType.RECONSTRUCT_MASTER_FAILED_NO_MASTER
: AuditLogType.RECONSTRUCT_MASTER_DONE : AuditLogType.RECONSTRUCT_MASTER_FAILED;
}
private static LogCompat log = LogFactoryCompat.getLog(ReconstructMasterDomainCommand.class);
}