package org.ovirt.engine.core.bll.exportimport;
import static org.ovirt.engine.core.bll.storage.disk.image.DisksFilter.ONLY_ACTIVE;
import static org.ovirt.engine.core.bll.storage.disk.image.DisksFilter.ONLY_NOT_SHAREABLE;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import org.apache.commons.lang.StringUtils;
import org.ovirt.engine.core.bll.Backend;
import org.ovirt.engine.core.bll.DisableInPrepareMode;
import org.ovirt.engine.core.bll.LockMessagesMatchUtil;
import org.ovirt.engine.core.bll.NonTransactiveCommandAttribute;
import org.ovirt.engine.core.bll.VmTemplateHandler;
import org.ovirt.engine.core.bll.context.CommandContext;
import org.ovirt.engine.core.bll.context.EngineContext;
import org.ovirt.engine.core.bll.memory.MemoryUtils;
import org.ovirt.engine.core.bll.snapshots.SnapshotsValidator;
import org.ovirt.engine.core.bll.storage.disk.image.DisksFilter;
import org.ovirt.engine.core.bll.storage.disk.image.ImagesHandler;
import org.ovirt.engine.core.bll.storage.ovfstore.OvfUpdateProcessHelper;
import org.ovirt.engine.core.bll.utils.ClusterUtils;
import org.ovirt.engine.core.bll.utils.PermissionSubject;
import org.ovirt.engine.core.bll.utils.VmOverheadCalculator;
import org.ovirt.engine.core.bll.validator.VmValidator;
import org.ovirt.engine.core.bll.validator.storage.DiskImagesValidator;
import org.ovirt.engine.core.bll.validator.storage.MultipleStorageDomainsValidator;
import org.ovirt.engine.core.bll.validator.storage.StorageDomainValidator;
import org.ovirt.engine.core.bll.validator.storage.StoragePoolValidator;
import org.ovirt.engine.core.common.AuditLogType;
import org.ovirt.engine.core.common.VdcObjectType;
import org.ovirt.engine.core.common.action.LockProperties;
import org.ovirt.engine.core.common.action.LockProperties.Scope;
import org.ovirt.engine.core.common.action.MoveOrCopyImageGroupParameters;
import org.ovirt.engine.core.common.action.MoveOrCopyParameters;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.action.VdcReturnValueBase;
import org.ovirt.engine.core.common.asynctasks.EntityInfo;
import org.ovirt.engine.core.common.businessentities.Snapshot;
import org.ovirt.engine.core.common.businessentities.Snapshot.SnapshotType;
import org.ovirt.engine.core.common.businessentities.StorageDomainStatic;
import org.ovirt.engine.core.common.businessentities.StorageDomainType;
import org.ovirt.engine.core.common.businessentities.StoragePoolIsoMapId;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.VmTemplate;
import org.ovirt.engine.core.common.businessentities.network.VmNetworkInterface;
import org.ovirt.engine.core.common.businessentities.storage.CopyVolumeType;
import org.ovirt.engine.core.common.businessentities.storage.Disk;
import org.ovirt.engine.core.common.businessentities.storage.DiskImage;
import org.ovirt.engine.core.common.businessentities.storage.ImageOperation;
import org.ovirt.engine.core.common.businessentities.storage.VolumeFormat;
import org.ovirt.engine.core.common.businessentities.storage.VolumeType;
import org.ovirt.engine.core.common.errors.EngineException;
import org.ovirt.engine.core.common.errors.EngineMessage;
import org.ovirt.engine.core.common.locks.LockingGroup;
import org.ovirt.engine.core.common.queries.GetAllFromExportDomainQueryParameters;
import org.ovirt.engine.core.common.queries.VdcQueryReturnValue;
import org.ovirt.engine.core.common.queries.VdcQueryType;
import org.ovirt.engine.core.common.utils.Pair;
import org.ovirt.engine.core.common.vdscommands.GetImageInfoVDSCommandParameters;
import org.ovirt.engine.core.common.vdscommands.UpdateVMVDSCommandParameters;
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.KeyValuePairCompat;
import org.ovirt.engine.core.dao.DiskImageDao;
import org.ovirt.engine.core.dao.SnapshotDao;
import org.ovirt.engine.core.dao.StorageDomainStaticDao;
import org.ovirt.engine.core.dao.StoragePoolIsoMapDao;
import org.ovirt.engine.core.dao.VmTemplateDao;
import org.ovirt.engine.core.dao.network.VmNetworkInterfaceDao;
import org.ovirt.engine.core.utils.GuidUtils;
import org.ovirt.engine.core.utils.ovf.OvfManager;
import org.ovirt.engine.core.utils.transaction.TransactionSupport;
@DisableInPrepareMode
@NonTransactiveCommandAttribute(forceCompensation = true)
public class ExportVmCommand<T extends MoveOrCopyParameters> extends MoveOrCopyTemplateCommand<T> {
@Inject
private OvfUpdateProcessHelper ovfUpdateProcessHelper;
private List<DiskImage> disksImages;
private Collection<Snapshot> snapshotsWithMemory;
@Inject
private VmOverheadCalculator vmOverheadCalculator;
@Inject
private OvfManager ovfManager;
@Inject
private SnapshotDao snapshotDao;
@Inject
private VmNetworkInterfaceDao vmNetworkInterfaceDao;
@Inject
private StoragePoolIsoMapDao storagePoolIsoMapDao;
@Inject
private SnapshotsValidator snapshotsValidator;
@Inject
private VmTemplateDao vmTemplateDao;
@Inject
private StorageDomainStaticDao storageDomainStaticDao;
@Inject
private DiskImageDao diskImageDao;
/**
* Constructor for command creation when compensation is applied on startup
*/
public ExportVmCommand(Guid commandId) {
super(commandId);
}
public ExportVmCommand(T parameters, CommandContext commandContext) {
super(parameters, commandContext);
setVmId(parameters.getContainerId());
parameters.setEntityInfo(new EntityInfo(VdcObjectType.VM, getVmId()));
}
@Override
protected LockProperties applyLockProperties(LockProperties lockProperties) {
return lockProperties.withScope(Scope.Execution);
}
@Override
protected boolean validate() {
if (getVm() == null) {
return failValidation(EngineMessage.ACTION_TYPE_FAILED_VM_NOT_FOUND);
}
setDescription(getVmName());
setStoragePoolId(getVm().getStoragePoolId());
// check that target domain exists
StorageDomainValidator targetstorageDomainValidator = new StorageDomainValidator(getStorageDomain());
if (!validate(targetstorageDomainValidator.isDomainExistAndActive())) {
return false;
}
// load the disks of vm from database
vmHandler.updateDisksFromDb(getVm());
List<DiskImage> disksForExport = getDisksBasedOnImage();
DiskImagesValidator diskImagesValidator = new DiskImagesValidator(disksForExport);
if (!validate(diskImagesValidator.diskImagesNotIllegal()) ||
!validate(diskImagesValidator.diskImagesNotLocked())) {
return false;
}
// update vm snapshots for storage free space check
ImagesHandler.fillImagesBySnapshots(getVm());
// check that the target and source domain are in the same storage_pool
if (storagePoolIsoMapDao.get(new StoragePoolIsoMapId(getStorageDomain().getId(),
getVm().getStoragePoolId())) == null) {
addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_STORAGE_POOL_NOT_MATCH);
return false;
}
// check if template exists only if asked for
if (getParameters().getTemplateMustExists()) {
if (!checkTemplateInStorageDomain(getVm().getStoragePoolId(), getParameters().getStorageDomainId(),
getVm().getVmtGuid(), getContext().getEngineContext())) {
return failValidation(EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_NOT_FOUND_ON_EXPORT_DOMAIN,
String.format("$TemplateName %1$s", getVm().getVmtName()));
}
}
// check that the images requested format are valid (COW+Sparse)
if (!ImagesHandler.checkImagesConfiguration(getParameters().getStorageDomainId(),
disksForExport,
getReturnValue().getValidationMessages())) {
return false;
}
Map<Guid, ? extends Disk> images = getVm().getDiskMap();
if (getParameters().getCopyCollapse()) {
for (DiskImage img : disksForExport) {
if (images.containsKey(img.getId())) {
// check that no RAW format exists (we are in collapse mode)
if (((DiskImage) images.get(img.getId())).getVolumeFormat() == VolumeFormat.RAW
&& img.getVolumeFormat() != VolumeFormat.RAW) {
addValidationMessage(EngineMessage.VM_CANNOT_EXPORT_RAW_FORMAT);
return false;
}
}
}
}
// check destination storage is Export domain
if (getStorageDomain().getStorageDomainType() != StorageDomainType.ImportExport) {
return failValidation(EngineMessage.ACTION_TYPE_FAILED_SPECIFY_DOMAIN_IS_NOT_EXPORT_DOMAIN,
String.format("$storageDomainName %1$s", getStorageDomainName()));
}
// get the snapshots that are going to be exported and have memory
snapshotsWithMemory = getSnapshotsToBeExportedWithMemory();
// check destination storage have free space
if (!handleDestStorageDomain(disksForExport)) {
return false;
}
if (!(checkVmInStorageDomain()
&& validate(new StoragePoolValidator(getStoragePool()).isUp())
&& validate(snapshotsValidator.vmNotDuringSnapshot(getVmId()))
&& validate(snapshotsValidator.vmNotInPreview(getVmId()))
&& validate(new VmValidator(getVm()).vmDown())
&& validate(new MultipleStorageDomainsValidator(getVm().getStoragePoolId(),
ImagesHandler.getAllStorageIdsForImageIds(disksForExport)).allDomainsExistAndActive()))) {
return false;
}
return true;
}
private boolean handleDestStorageDomain(List<DiskImage> disksList) {
ensureDomainMap(disksList, getStorageDomainId());
List<DiskImage> dummiesDisksList = createDiskDummiesForSpaceValidations(disksList);
dummiesDisksList.addAll(getMemoryVolumes());
return validateSpaceRequirements(dummiesDisksList);
}
/**
* Space Validations are done using data extracted from the disks. The disks in question in this command
* don't have all the needed data, and in order not to contaminate the command's data structures, an alter
* one is created specifically fo this validation - hence dummy.
*/
protected List<DiskImage> createDiskDummiesForSpaceValidations(List<DiskImage> disksList) {
List<DiskImage> dummies = new ArrayList<>(disksList.size());
for (DiskImage image : disksList) {
Guid targetSdId = imageToDestinationDomainMap.get(image.getId());
DiskImage dummy = ImagesHandler.createDiskImageWithExcessData(image, targetSdId);
dummies.add(dummy);
}
return dummies;
}
private List<DiskImage> getMemoryVolumes() {
int numOfSnapshots = snapshotsWithMemory.size();
long memorySize = numOfSnapshots * vmOverheadCalculator.getSnapshotMemorySizeInBytes(getVm());
long metadataSize = numOfSnapshots * MemoryUtils.METADATA_SIZE_IN_BYTES;
List<DiskImage> memoryDisksList = MemoryUtils.createDiskDummies(memorySize, metadataSize);
//Set target domain in memory disks
ArrayList<Guid> sdId = new ArrayList<>(Collections.singletonList(getStorageDomainId()));
for (DiskImage diskImage : memoryDisksList) {
diskImage.setStorageIds(sdId);
}
return memoryDisksList;
}
private Collection<Snapshot> getSnapshotsToBeExportedWithMemory() {
if (getParameters().getCopyCollapse()) {
Snapshot activeSnapshot = snapshotDao.get(getVmId(), SnapshotType.ACTIVE);
return !activeSnapshot.getMemoryVolume().isEmpty() ?
Collections.singleton(activeSnapshot) : Collections.emptyList();
}
else {
Map<String, Snapshot> memory2snapshot = new HashMap<>();
for (Snapshot snapshot : snapshotDao.getAll(getVmId())) {
memory2snapshot.put(snapshot.getMemoryVolume(), snapshot);
}
memory2snapshot.remove(StringUtils.EMPTY);
return memory2snapshot.values();
}
}
@Override
protected void setActionMessageParameters() {
addValidationMessage(EngineMessage.VAR__ACTION__EXPORT);
addValidationMessage(EngineMessage.VAR__TYPE__VM);
}
@Override
protected void executeCommand() {
vmHandler.lockVm(getVm().getDynamicData(), getCompensationContext());
freeLock();
// update vm init
vmHandler.updateVmInitFromDB(getVm().getStaticData(), true);
// Means that there are no asynchronous tasks to execute - so we can end the command
// immediately after the execution of the previous steps
if (!hasSnappableDisks() && snapshotsWithMemory.isEmpty()) {
endSuccessfully();
} else {
TransactionSupport.executeInNewTransaction(() -> {
moveOrCopyAllImageGroups();
return null;
});
if (!getReturnValue().getVdsmTaskIdList().isEmpty()) {
setSucceeded(true);
}
}
}
private boolean hasSnappableDisks() {
return !getDisksBasedOnImage().isEmpty();
}
private boolean updateCopyVmInSpm(Guid storagePoolId, VM vm, Guid storageDomainId) {
HashMap<Guid, KeyValuePairCompat<String, List<Guid>>> vmsAndMetaDictionary = new HashMap<>();
ArrayList<DiskImage> AllVmImages = new ArrayList<>();
List<VmNetworkInterface> interfaces = vm.getInterfaces();
if (interfaces != null) {
// TODO remove this when the API changes
interfaces.clear();
interfaces.addAll(vmNetworkInterfaceDao.getAllForVm(vm.getId()));
}
List<Guid> imageGroupIds = new ArrayList<>();
for (Disk disk : getDisksBasedOnImage()) {
DiskImage diskImage = (DiskImage) disk;
diskImage.setParentId(VmTemplateHandler.BLANK_VM_TEMPLATE_ID);
diskImage.setImageTemplateId(VmTemplateHandler.BLANK_VM_TEMPLATE_ID);
diskImage.setStorageIds(new ArrayList<>(Collections.singletonList(storageDomainId)));
DiskImage diskForVolumeInfo = getDiskForVolumeInfo(diskImage);
diskImage.setVolumeFormat(diskForVolumeInfo.getVolumeFormat());
diskImage.setVolumeType(diskForVolumeInfo.getVolumeType());
VDSReturnValue vdsReturnValue = runVdsCommand(
VDSCommandType.GetImageInfo,
new GetImageInfoVDSCommandParameters(storagePoolId, storageDomainId, diskImage
.getId(), diskImage.getImageId()));
if (vdsReturnValue != null && vdsReturnValue.getSucceeded()) {
DiskImage fromVdsm = (DiskImage) vdsReturnValue.getReturnValue();
diskImage.setActualSizeInBytes(fromVdsm.getActualSizeInBytes());
}
AllVmImages.add(diskImage);
imageGroupIds.add(disk.getId());
}
if (StringUtils.isEmpty(vm.getVmtName())) {
VmTemplate t = vmTemplateDao.get(vm.getVmtGuid());
vm.setVmtName(t.getName());
}
getVm().setVmtGuid(VmTemplateHandler.BLANK_VM_TEMPLATE_ID);
String vmMeta = ovfManager.exportVm(vm, AllVmImages, ClusterUtils.getCompatibilityVersion(vm));
vmsAndMetaDictionary.put(vm.getId(), new KeyValuePairCompat<>(vmMeta, imageGroupIds));
UpdateVMVDSCommandParameters tempVar = new UpdateVMVDSCommandParameters(storagePoolId, vmsAndMetaDictionary);
tempVar.setStorageDomainId(storageDomainId);
return runVdsCommand(VDSCommandType.UpdateVM, tempVar)
.getSucceeded();
}
@Override
protected void moveOrCopyAllImageGroups() {
// Disks
moveOrCopyAllImageGroups(getVm().getId(), getDisksBasedOnImage());
// Memory volumes
copyAllMemoryImages(getVm().getId());
}
private List<DiskImage> getDisksBasedOnImage() {
if (disksImages == null) {
disksImages = DisksFilter.filterImageDisks(getVm().getDiskMap().values(), ONLY_NOT_SHAREABLE, ONLY_ACTIVE);
}
return disksImages;
}
private void copyAllMemoryImages(Guid containerID) {
for (Snapshot snapshot : snapshotsWithMemory) {
List<Guid> guids = GuidUtils.getGuidListFromString(snapshot.getMemoryVolume());
// copy the memory dump image
VdcReturnValueBase vdcRetValue = runInternalActionWithTasksContext(
VdcActionType.CopyImageGroup,
buildMoveOrCopyImageGroupParametersForMemoryDumpImage(
containerID, guids.get(0), guids.get(2), guids.get(3)));
if (!vdcRetValue.getSucceeded()) {
throw new EngineException(vdcRetValue.getFault().getError(), "Failed during ExportVmCommand");
}
getReturnValue().getVdsmTaskIdList().addAll(vdcRetValue.getInternalVdsmTaskIdList());
// copy the memory configuration (of the VM) image
vdcRetValue = runInternalActionWithTasksContext(
VdcActionType.CopyImageGroup,
buildMoveOrCopyImageGroupParametersForMemoryConfImage(
containerID, guids.get(0), guids.get(4), guids.get(5)));
if (!vdcRetValue.getSucceeded()) {
throw new EngineException(vdcRetValue.getFault().getError(), "Failed during ExportVmCommand");
}
getReturnValue().getVdsmTaskIdList().addAll(vdcRetValue.getInternalVdsmTaskIdList());
}
}
private MoveOrCopyImageGroupParameters buildMoveOrCopyImageGroupParametersForMemoryDumpImage(
Guid containerID, Guid storageDomainId, Guid imageId, Guid volumeId) {
MoveOrCopyImageGroupParameters params = new MoveOrCopyImageGroupParameters(containerID, imageId,
volumeId, getParameters().getStorageDomainId(), ImageOperation.Copy);
params.setParentCommand(getActionType());
params.setCopyVolumeType(CopyVolumeType.LeafVol);
params.setForceOverride(getParameters().getForceOverride());
params.setSourceDomainId(storageDomainId);
params.setEntityInfo(getParameters().getEntityInfo());
params.setParentParameters(getParameters());
StorageDomainStatic sourceDomain = storageDomainStaticDao.get(storageDomainId);
// if the data domain is a block based storage, the memory volume type is preallocated
// so we need to use copy collapse in order to convert it to be sparsed in the export domain
if (sourceDomain.getStorageType().isBlockDomain()) {
params.setUseCopyCollapse(true);
params.setVolumeType(VolumeType.Sparse);
params.setVolumeFormat(VolumeFormat.RAW);
}
return params;
}
private MoveOrCopyImageGroupParameters buildMoveOrCopyImageGroupParametersForMemoryConfImage(
Guid containerID, Guid storageDomainId, Guid imageId, Guid volumeId) {
MoveOrCopyImageGroupParameters params = new MoveOrCopyImageGroupParameters(containerID, imageId,
volumeId, getParameters().getStorageDomainId(), ImageOperation.Copy);
params.setParentCommand(getActionType());
// This volume is always of type 'sparse' and format 'cow' so no need to convert,
// and there're no snapshots for it so no reason to use copy collapse
params.setUseCopyCollapse(false);
params.setEntityInfo(getParameters().getEntityInfo());
params.setCopyVolumeType(CopyVolumeType.LeafVol);
params.setForceOverride(getParameters().getForceOverride());
params.setParentParameters(getParameters());
params.setSourceDomainId(storageDomainId);
return params;
}
@Override
protected void moveOrCopyAllImageGroups(Guid containerID, Iterable<DiskImage> disks) {
for (DiskImage disk : disks) {
VdcReturnValueBase vdcRetValue = runInternalActionWithTasksContext(
VdcActionType.CopyImageGroup,
buildMoveOrCopyImageGroupParametersForDisk(containerID, disk));
if (!vdcRetValue.getSucceeded()) {
throw new EngineException(vdcRetValue.getFault().getError(), "Failed during ExportVmCommand");
}
getReturnValue().getVdsmTaskIdList().addAll(vdcRetValue.getInternalVdsmTaskIdList());
}
}
private MoveOrCopyImageGroupParameters buildMoveOrCopyImageGroupParametersForDisk(Guid containerID, DiskImage disk) {
MoveOrCopyImageGroupParameters params = new MoveOrCopyImageGroupParameters(containerID, disk.getId(),
disk.getImageId(), getParameters().getStorageDomainId(), ImageOperation.Copy);
params.setParentCommand(getActionType());
params.setEntityInfo(getParameters().getEntityInfo());
params.setUseCopyCollapse(getParameters().getCopyCollapse());
DiskImage diskForVolumeInfo = getDiskForVolumeInfo(disk);
params.setVolumeFormat(diskForVolumeInfo.getVolumeFormat());
params.setVolumeType(diskForVolumeInfo.getVolumeType());
params.setCopyVolumeType(CopyVolumeType.LeafVol);
params.setForceOverride(getParameters().getForceOverride());
params.setParentParameters(getParameters());
return params;
}
/**
* Return the correct disk to get the volume info (type & allocation) from. For copy collapse it's the ancestral
* disk of the given disk, and otherwise it's the disk itself.
*
* @param disk
* The disk for which to get the disk with the info.
* @return The disk with the correct volume info.
*/
private DiskImage getDiskForVolumeInfo(DiskImage disk) {
if (getParameters().getCopyCollapse()) {
return diskImageDao.getAncestor(disk.getImageId());
} else {
return disk;
}
}
/**
* Check that vm is in export domain
*/
protected boolean checkVmInStorageDomain() {
boolean retVal = true;
GetAllFromExportDomainQueryParameters tempVar = new GetAllFromExportDomainQueryParameters(getVm()
.getStoragePoolId(), getParameters().getStorageDomainId());
VdcQueryReturnValue qretVal = runInternalQuery(VdcQueryType.GetVmsFromExportDomain,
tempVar);
if (qretVal.getSucceeded()) {
ArrayList<VM> vms = qretVal.getReturnValue();
for (VM vm : vms) {
if (vm.getId().equals(getVm().getId())) {
if (!getParameters().getForceOverride()) {
addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_VM_GUID_ALREADY_EXIST);
retVal = false;
break;
}
} else if (vm.getName().equals(getVm().getName())) {
addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_NAME_ALREADY_USED);
retVal = false;
break;
}
}
}
return retVal;
}
public static boolean checkTemplateInStorageDomain(Guid storagePoolId,
Guid storageDomainId,
final Guid tmplId,
EngineContext engineContext) {
boolean retVal = false;
GetAllFromExportDomainQueryParameters tempVar = new GetAllFromExportDomainQueryParameters(storagePoolId,
storageDomainId);
VdcQueryReturnValue qretVal = Backend.getInstance().runInternalQuery(VdcQueryType.GetTemplatesFromExportDomain,
tempVar, engineContext);
if (qretVal.getSucceeded()) {
if (!VmTemplateHandler.BLANK_VM_TEMPLATE_ID.equals(tmplId)) {
Map<VmTemplate, List<DiskImage>> templates = qretVal.getReturnValue();
retVal = templates.keySet().stream().anyMatch(vmTemplate -> vmTemplate.getId().equals(tmplId));
} else {
retVal = true;
}
}
return retVal;
}
@Override
public AuditLogType getAuditLogTypeValue() {
switch (getActionState()) {
case EXECUTE:
return getSucceeded() ? AuditLogType.IMPORTEXPORT_STARTING_EXPORT_VM
: AuditLogType.IMPORTEXPORT_EXPORT_VM_FAILED;
case END_SUCCESS:
return getSucceeded() ? AuditLogType.IMPORTEXPORT_EXPORT_VM : AuditLogType.IMPORTEXPORT_EXPORT_VM_FAILED;
default:
return AuditLogType.IMPORTEXPORT_EXPORT_VM_FAILED;
}
}
protected boolean updateVmInSpm() {
Map<Guid, KeyValuePairCompat<String, List<Guid>>> metaDictionary = new HashMap<>();
ovfUpdateProcessHelper.loadVmData(getVm());
ovfUpdateProcessHelper.buildMetadataDictionaryForVm(getVm(),
metaDictionary,
ovfUpdateProcessHelper.getVmImagesFromDb(getVm()));
return ovfUpdateProcessHelper.executeUpdateVmInSpmCommand(getVm().getStoragePoolId(),
metaDictionary, getParameters().getStorageDomainId());
}
@Override
protected void endSuccessfully() {
endActionOnAllImageGroups();
VM vm = getVm();
populateVmData(vm);
if (getParameters().getCopyCollapse()) {
endCopyCollapseOperations(vm);
} else {
updateSnapshotOvf(vm);
}
vmHandler.unLockVm(vm);
setSucceeded(true);
}
private void populateVmData(VM vm) {
vmHandler.updateDisksFromDb(vm);
vmHandler.updateVmInitFromDB(vm.getStaticData(), true);
getVmDeviceUtils().setVmDevices(vm.getStaticData());
}
private void endCopyCollapseOperations(VM vm) {
vm.setVmtGuid(VmTemplateHandler.BLANK_VM_TEMPLATE_ID);
vm.setVmtName(null);
Snapshot activeSnapshot = snapshotDao.get(snapshotDao.getId(vm.getId(), SnapshotType.ACTIVE));
vm.setSnapshots(Collections.singletonList(activeSnapshot));
try {
updateCopyVmInSpm(getVm().getStoragePoolId(),
vm, getParameters()
.getStorageDomainId());
}
catch (EngineException e) {
log.error("Updating VM OVF in export domain failed.", e);
auditLogDirector.log(this, AuditLogType.IMPORTEXPORT_IMPORT_VM_FAILED_UPDATING_OVF);
}
}
private void updateSnapshotOvf(VM vm) {
vm.setSnapshots(snapshotDao.getAllWithConfiguration(getVm().getId()));
updateVmInSpm();
}
@Override
protected Map<String, Pair<String, String>> getExclusiveLocks() {
return Collections.singletonMap(getVmId().toString(),
LockMessagesMatchUtil.makeLockingPair(LockingGroup.VM, EngineMessage.ACTION_TYPE_FAILED_OBJECT_LOCKED));
}
@Override
protected void endWithFailure() {
endActionOnAllImageGroups();
VM vm = getVm();
vmHandler.unLockVm(vm);
setSucceeded(true);
}
@Override
public Map<String, String> getJobMessageProperties() {
if (jobProperties == null) {
jobProperties = super.getJobMessageProperties();
jobProperties.put(VdcObjectType.VM.name().toLowerCase(),
(getVmName() == null) ? "" : getVmName());
}
return jobProperties;
}
@Override
public List<PermissionSubject> getPermissionCheckSubjects() {
List<PermissionSubject> permissionSubjects = new ArrayList<>();
permissionSubjects.addAll(super.getPermissionCheckSubjects());
permissionSubjects.add(new PermissionSubject(getVmId(), VdcObjectType.VM, getActionType().getActionGroup()));
return permissionSubjects;
}
}