package org.ovirt.engine.core.bll.storage.disk.cinder;
import java.util.Collection;
import java.util.Collections;
import javax.inject.Inject;
import org.ovirt.engine.core.bll.InternalCommandAttribute;
import org.ovirt.engine.core.bll.context.CommandContext;
import org.ovirt.engine.core.bll.storage.disk.image.BaseImagesCommand;
import org.ovirt.engine.core.bll.storage.disk.image.ImagesHandler;
import org.ovirt.engine.core.bll.tasks.interfaces.CommandCallback;
import org.ovirt.engine.core.common.VdcObjectType;
import org.ovirt.engine.core.common.action.ImagesContainterParametersBase;
import org.ovirt.engine.core.common.action.RemoveCinderDiskParameters;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.businessentities.SubjectEntity;
import org.ovirt.engine.core.common.businessentities.storage.CinderDisk;
import org.ovirt.engine.core.common.businessentities.storage.DiskImageDynamic;
import org.ovirt.engine.core.common.businessentities.storage.ImageStatus;
import org.ovirt.engine.core.common.businessentities.storage.ImageStorageDomainMap;
import org.ovirt.engine.core.common.businessentities.storage.VolumeClassification;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.dao.BaseDiskDao;
import org.ovirt.engine.core.dao.DiskImageDao;
import org.ovirt.engine.core.dao.DiskImageDynamicDao;
import org.ovirt.engine.core.dao.ImageDao;
import org.ovirt.engine.core.dao.ImageStorageDomainMapDao;
import org.ovirt.engine.core.di.Injector;
import org.ovirt.engine.core.utils.transaction.TransactionSupport;
@InternalCommandAttribute
public class CloneSingleCinderDiskCommand<T extends ImagesContainterParametersBase> extends BaseImagesCommand<T> {
private CinderDisk disk;
@Inject
private BaseDiskDao baseDiskDao;
@Inject
private ImageDao imageDao;
@Inject
private DiskImageDynamicDao diskImageDynamicDao;
@Inject
private ImageStorageDomainMapDao imageStorageDomainMapDao;
@Inject
private DiskImageDao diskImageDao;
public CloneSingleCinderDiskCommand(T parameters, CommandContext commandContext) {
super(parameters, commandContext);
setStorageDomainId(parameters.getStorageDomainId());
}
@Override
protected void executeCommand() {
lockImage();
CinderDisk cinderDisk = getDisk();
cinderDisk.setDiskAlias(getParameters().getDiskAlias());
String volumeId = getNewVolumeCinderDisk(cinderDisk);
cinderDisk.setId(Guid.createGuidFromString(volumeId));
cinderDisk.setImageId(Guid.createGuidFromString(volumeId));
cinderDisk.setImageStatus(ImageStatus.LOCKED);
cinderDisk.setVolumeClassification(VolumeClassification.Volume);
cinderDisk.setVmSnapshotId(getParameters().getVmSnapshotId());
// If we clone a disk from snapshot, update the volume with the appropriate parameters.
if (!cinderDisk.getActive()) {
cinderDisk.setActive(true);
cinderDisk.setParentId(Guid.Empty);
}
addCinderDiskTemplateToDB(cinderDisk);
getReturnValue().setActionReturnValue(cinderDisk.getId());
getParameters().setDestinationImageId(Guid.createGuidFromString(volumeId));
getParameters().setContainerId(Guid.createGuidFromString(volumeId));
persistCommand(getParameters().getParentCommand(), true);
setSucceeded(true);
}
private String getNewVolumeCinderDisk(CinderDisk cinderDisk) {
String volumeId;
if (cinderDisk.getActive()) {
volumeId = getCinderBroker().cloneDisk(cinderDisk);
} else {
volumeId = getCinderBroker().cloneVolumeFromSnapshot(cinderDisk, cinderDisk.getImageId());
}
return volumeId;
}
protected void addCinderDiskTemplateToDB(final CinderDisk cinderDisk) {
TransactionSupport.executeInNewTransaction(() -> {
baseDiskDao.save(cinderDisk);
imageDao.save(cinderDisk.getImage());
DiskImageDynamic diskDynamic = new DiskImageDynamic();
diskDynamic.setId(cinderDisk.getImageId());
diskImageDynamicDao.save(diskDynamic);
ImageStorageDomainMap image_storage_domain_map = new ImageStorageDomainMap(cinderDisk.getImageId(),
cinderDisk.getStorageIds().get(0), cinderDisk.getQuotaId(), cinderDisk.getDiskProfileId());
imageStorageDomainMapDao.save(image_storage_domain_map);
getCompensationContext().snapshotNewEntity(image_storage_domain_map);
getCompensationContext().snapshotNewEntity(diskDynamic);
getCompensationContext().snapshotNewEntity(cinderDisk.getImage());
getCompensationContext().snapshotNewEntity(cinderDisk);
getCompensationContext().stateChanged();
return null;
});
}
protected CinderDisk getDisk() {
if (disk == null) {
disk = (CinderDisk) diskImageDao.getSnapshotById(getImageId());
}
return disk;
}
@Override
protected void lockImage() {
ImagesHandler.updateImageStatus(getParameters().getImageId(), ImageStatus.LOCKED);
}
@Override
public CommandCallback getCallback() {
return Injector.injectMembers(new CloneSingleCinderDiskCommandCallback());
}
@Override
protected void endSuccessfully() {
ImagesHandler.updateImageStatus(getParameters().getDestinationImageId(), ImageStatus.OK);
ImagesHandler.updateImageStatus(getParameters().getImageId(), ImageStatus.OK);
setSucceeded(true);
}
@Override
protected void endWithFailure() {
ImagesHandler.updateImageStatus(getParameters().getDestinationImageId(), ImageStatus.ILLEGAL);
removeCinderDisk();
ImagesHandler.updateImageStatus(getParameters().getImageId(), ImageStatus.OK);
setSucceeded(true);
}
@Override
protected Collection<SubjectEntity> getSubjectEntities() {
return Collections.singleton(new SubjectEntity(VdcObjectType.Storage, getStorageDomainId()));
}
private void removeCinderDisk() {
runInternalAction(VdcActionType.RemoveCinderDisk,
buildRevertParameters(getParameters().getDestinationImageId()),
null);
}
private RemoveCinderDiskParameters buildRevertParameters(Guid cinderDiskId) {
RemoveCinderDiskParameters removeDiskParams = new RemoveCinderDiskParameters(cinderDiskId);
removeDiskParams.setLockVM(false);
removeDiskParams.setShouldBeLogged(false);
return removeDiskParams;
}
}