package org.ovirt.engine.core.bll.memory;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.ovirt.engine.core.bll.Backend;
import org.ovirt.engine.core.bll.CommandBase;
import org.ovirt.engine.core.bll.tasks.CommandCoordinatorUtil;
import org.ovirt.engine.core.common.businessentities.storage.Disk;
import org.ovirt.engine.core.common.errors.EngineError;
import org.ovirt.engine.core.common.errors.EngineException;
import org.ovirt.engine.core.common.errors.VDSError;
import org.ovirt.engine.core.common.vdscommands.DeleteImageGroupVDSCommandParameters;
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.dal.dbbroker.DbFacade;
import org.ovirt.engine.core.dao.DiskDao;
import org.ovirt.engine.core.utils.GuidUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class MemoryImageRemover {
private static final Logger log = LoggerFactory.getLogger(MemoryImageRemover.class);
private static final int NUM_OF_UUIDS_IN_MEMORY_STATE = 6;
public static final String DELETE_PRIMARY_IMAGE_TASK_KEY = "DELETE_PRIMARY_IMAGE_TASK_KEY";
public static final String DELETE_SECONDARY_IMAGES_TASK_KEY = "DELETE_SECONDARY_IMAGES_TASK_KEY";
protected final CommandBase<?> enclosingCommand;
private boolean startPollingTasks;
public MemoryImageRemover(CommandBase<?> enclosingCommand) {
this.enclosingCommand = enclosingCommand;
}
public MemoryImageRemover(CommandBase<?> enclosingCommand, boolean startPollingTasks) {
this(enclosingCommand);
this.startPollingTasks = startPollingTasks;
}
protected abstract DeleteImageGroupVDSCommandParameters buildDeleteMemoryImageParams(List<Guid> guids);
protected abstract DeleteImageGroupVDSCommandParameters buildDeleteMemoryConfParams(List<Guid> guids);
protected Guid createTask(Guid taskId, VDSReturnValue vdsRetValue) {
return enclosingCommand.createTask(
taskId,
vdsRetValue.getCreationInfo(),
enclosingCommand.getActionType());
}
/**
* Default implementation checks whether the memory state representation is not empty
*/
protected boolean isMemoryStateRemovable(String memoryVolume) {
return !memoryVolume.isEmpty();
}
protected boolean removeMemoryVolume(String memoryVolumes) {
if (isMemoryStateRemovable(memoryVolumes)) {
return removeMemoryVolumes(memoryVolumes);
}
return true;
}
/**
* Try to remove all the given memory volumes
*
* @param memoryVolumes - memory volumes to remove
* @return true if all the memory volumes were removed successfully, false otherwise
*/
protected boolean removeMemoryVolumes(Set<String> memoryVolumes) {
boolean allVolumesRemovedSucessfully = true;
for (String memoryVols : memoryVolumes) {
allVolumesRemovedSucessfully &= removeMemoryVolume(memoryVols);
}
return allVolumesRemovedSucessfully;
}
private boolean removeMemoryVolumes(String memVols) {
List<Guid> guids = GuidUtils.getGuidListFromString(memVols);
if (guids.size() != NUM_OF_UUIDS_IN_MEMORY_STATE) {
log.warn("Cannot remove memory volumes, invalid format '{}'", memVols);
return true;
}
Guid memoryImageRemovalTaskId = removeMemoryImage(guids);
if (memoryImageRemovalTaskId == null) {
return false;
}
Guid confImageRemovalTaskId = removeConfImage(guids);
if (startPollingTasks) {
if (!Guid.Empty.equals(memoryImageRemovalTaskId)) {
CommandCoordinatorUtil.startPollingTask(memoryImageRemovalTaskId);
}
if (confImageRemovalTaskId != null && !Guid.Empty.equals(confImageRemovalTaskId)) {
CommandCoordinatorUtil.startPollingTask(confImageRemovalTaskId);
}
}
return confImageRemovalTaskId != null;
}
protected Guid removeMemoryImage(List<Guid> guids) {
return removeImage(
DELETE_PRIMARY_IMAGE_TASK_KEY,
buildDeleteMemoryImageParams(guids));
}
protected Guid removeConfImage(List<Guid> guids) {
return removeImage(
DELETE_SECONDARY_IMAGES_TASK_KEY,
buildDeleteMemoryConfParams(guids));
}
protected Guid removeImage(String taskKey, DeleteImageGroupVDSCommandParameters parameters) {
Guid taskId = enclosingCommand.persistAsyncTaskPlaceHolder(enclosingCommand.getActionType(), taskKey);
VDSReturnValue vdsRetValue = removeImage(parameters);
// if command succeeded, create a task
if (vdsRetValue.getSucceeded()) {
Guid guid = createTask(taskId, vdsRetValue);
enclosingCommand.getTaskIdList().add(guid);
return guid;
}
else {
boolean imageDoesNotExist = vdsRetValue.getVdsError().getCode() == EngineError.ImageDoesNotExistInDomainError;
if (!imageDoesNotExist) {
log.error("Could not remove memory image '{}'", parameters);
}
enclosingCommand.deleteAsyncTaskPlaceHolder(taskKey);
// otherwise, if the command failed because the image does not exist,
// no need to create and monitor task, so we return empty guid to mark this state
return imageDoesNotExist ? Guid.Empty : null;
}
}
protected VDSReturnValue removeImage(DeleteImageGroupVDSCommandParameters parameters) {
try {
return Backend.getInstance().getResourceManager().runVdsCommand(
VDSCommandType.DeleteImageGroup,
parameters);
}
catch(EngineException e) {
if (e.getErrorCode() == EngineError.ImageDoesNotExistInDomainError) {
return createImageDoesNotExistInDomainReturnValue();
}
throw e;
}
}
protected VDSReturnValue createImageDoesNotExistInDomainReturnValue() {
VDSReturnValue vdsRetValue = new VDSReturnValue();
vdsRetValue.setSucceeded(false);
vdsRetValue.setVdsError(new VDSError(EngineError.ImageDoesNotExistInDomainError, ""));
return vdsRetValue;
}
/**
* @return true IFF one of the given disks is marked with wipe_after_delete
*/
protected static boolean isDiskWithWipeAfterDeleteExist(Collection<Disk> disks) {
for (Disk disk : disks) {
if (disk.isWipeAfterDelete()) {
return true;
}
}
return false;
}
protected DiskDao getDiskDao() {
return DbFacade.getInstance().getDiskDao();
}
}