package org.ovirt.engine.core.bll.storage.disk.image;
import static org.ovirt.engine.core.common.constants.StorageConstants.ENTITY_FENCING_GENERATION_DIFF;
import org.ovirt.engine.core.bll.InternalCommandAttribute;
import org.ovirt.engine.core.bll.NonTransactiveCommandAttribute;
import org.ovirt.engine.core.bll.context.CommandContext;
import org.ovirt.engine.core.bll.storage.StorageJobCommand;
import org.ovirt.engine.core.bll.storage.utils.VdsCommandsHelper;
import org.ovirt.engine.core.bll.tasks.CommandCoordinatorUtil;
import org.ovirt.engine.core.common.action.FenceVolumeJobCommandParameters;
import org.ovirt.engine.core.common.vdscommands.UpdateVolumeVDSCommandParameters;
import org.ovirt.engine.core.common.vdscommands.VDSCommandType;
@NonTransactiveCommandAttribute
@InternalCommandAttribute
public class FenceVolumeJobCommand<T extends FenceVolumeJobCommandParameters> extends StorageJobCommand<T> {
public FenceVolumeJobCommand(T parameters, CommandContext cmdContext) {
super(parameters, cmdContext);
}
@Override
protected void executeCommand() {
UpdateVolumeVDSCommandParameters p = new UpdateVolumeVDSCommandParameters(getParameters().getStorageJobId(),
getParameters().getImageLocationInfo());
p.setGeneration(getParameters().getImageLocationInfo().getGeneration() + ENTITY_FENCING_GENERATION_DIFF);
VdsCommandsHelper.runVdsCommandWithoutFailover(VDSCommandType.UpdateVolume,
p,
getParameters().getStoragePoolId(),
this);
setSucceeded(true);
}
@Override
public boolean failJobWithUndeterminedStatus() {
// We are fine with failing this operation if the job status is undetermined due to any reason, on the worst
// case another FenceVolumeJobCommand call will be executed and this job will silently fail because of an
// unmatched generation.
return true;
}
@Override
protected void endSuccessfully() {
endActions();
}
@Override
protected void endWithFailure() {
endActions();
}
private void endActions() {
// FenceVolumeJob is executed in order to fence operations that were submitted and are supposed
// to be performed on the volume.
// In case of failure to fence an operation, the engine may attempt to fence it again - when the fencing
// fails constantly the number of commands will grow indefinitely. As we store a record for each command in
// the commands table - that's something we should avoid.
// The engine uses the command record just for polling (to avoid executing another fence operation before the
// previous one ended) and not for determining if the fencing succeeded (it polls the entity to verify that),
// therefore we are fine with deleting the command entity after the execution ends.
CommandCoordinatorUtil.removeAllCommandsInHierarchy(getCommandId());
}
}