package org.ovirt.engine.core.bll.storage.disk.image;
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.CommandBase;
import org.ovirt.engine.core.bll.InternalCommandAttribute;
import org.ovirt.engine.core.bll.NonTransactiveCommandAttribute;
import org.ovirt.engine.core.bll.SerialChildCommandsExecutionCallback;
import org.ovirt.engine.core.bll.SerialChildExecutingCommand;
import org.ovirt.engine.core.bll.context.CommandContext;
import org.ovirt.engine.core.bll.tasks.interfaces.CommandCallback;
import org.ovirt.engine.core.bll.utils.CommandsWeightsUtils;
import org.ovirt.engine.core.bll.utils.PermissionSubject;
import org.ovirt.engine.core.common.action.CopyDataCommandParameters;
import org.ovirt.engine.core.common.action.CopyImageGroupVolumesDataCommandParameters;
import org.ovirt.engine.core.common.action.VdcActionParametersBase.EndProcedure;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.businessentities.LocationInfo;
import org.ovirt.engine.core.common.businessentities.VdsmImageLocationInfo;
import org.ovirt.engine.core.common.businessentities.storage.DiskImage;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.dao.DiskImageDao;
@InternalCommandAttribute
@NonTransactiveCommandAttribute
public class CopyImageGroupVolumesDataCommand<T extends CopyImageGroupVolumesDataCommandParameters>
extends CommandBase<T> implements SerialChildExecutingCommand {
@Inject
private CommandsWeightsUtils commandsWeightsUtils;
@Inject
private DiskImageDao diskImageDao;
public CopyImageGroupVolumesDataCommand(T parameters, CommandContext cmdContext) {
super(parameters, cmdContext);
setStoragePoolId(getParameters().getStoragePoolId());
}
private double calculateImageWeight(double totalSize, DiskImage image) {
return totalSize == 0 ? 1d / getParameters().getImageIds().size() : image.getActualSize() / totalSize;
}
@Override
protected void executeCommand() {
List<DiskImage> images = diskImageDao
.getAllSnapshotsForImageGroup(getParameters().getImageGroupID());
ImagesHandler.sortImageList(images);
getParameters().setImageIds(ImagesHandler.getDiskImageIds(images));
prepareWeights(images);
persistCommand(getParameters().getParentCommand(), getCallback() != null);
setSucceeded(true);
}
private void prepareWeights(List<DiskImage> images) {
if (getParameters().getJobWeight() != null) {
double totalSize = images.stream().mapToDouble(DiskImage::getActualSize).sum();
Map<String, Double> weightDivision = images.stream().collect(
Collectors.toMap(x -> x.getImageId().toString(), x -> calculateImageWeight(totalSize, x)));
getParameters().setOperationsJobWeight(commandsWeightsUtils.adjust(weightDivision,
getParameters().getJobWeight()));
}
}
@Override
public List<PermissionSubject> getPermissionCheckSubjects() {
return Collections.emptyList();
}
@Override
public CommandCallback getCallback() {
return new SerialChildCommandsExecutionCallback();
}
@Override
public boolean performNextOperation(int completedChildren) {
if (completedChildren == getParameters().getImageIds().size()) {
return false;
}
Guid imageId = getParameters().getImageIds().get(completedChildren);
log.info("Starting child command {} of {}, image '{}'",
completedChildren + 1, getParameters().getImageIds().size(), imageId);
copyVolumeData(imageId);
return true;
}
private void copyVolumeData(Guid image) {
CopyDataCommandParameters parameters = new CopyDataCommandParameters(getParameters().getStoragePoolId(),
buildImageLocationInfo(getParameters().getSrcDomain(), getParameters().getImageGroupID(),
image),
buildImageLocationInfo(getParameters().getDestDomain(), getParameters().getImageGroupID(),
image), false);
parameters.setEndProcedure(EndProcedure.COMMAND_MANAGED);
parameters.setParentCommand(getActionType());
parameters.setParentParameters(getParameters());
parameters.setJobWeight(getParameters().getOperationsJobWeight().get(image.toString()));
runInternalActionWithTasksContext(VdcActionType.CopyData, parameters);
}
@Override
public void handleFailure() {
}
private LocationInfo buildImageLocationInfo(Guid domId, Guid imageGroupId, Guid imageId) {
return new VdsmImageLocationInfo(domId, imageGroupId, imageId, null);
}
}