package org.ovirt.engine.core.bll; import java.util.List; import java.util.Map; import org.ovirt.engine.core.bll.command.utils.StorageDomainSpaceChecker; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.action.MoveOrCopyImageGroupParameters; import org.ovirt.engine.core.common.action.MoveVmParameters; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.action.VdcReturnValueBase; import org.ovirt.engine.core.common.businessentities.CopyVolumeType; import org.ovirt.engine.core.common.businessentities.DiskImage; import org.ovirt.engine.core.common.businessentities.DiskImageBase; 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.VmNetworkInterface; import org.ovirt.engine.core.common.businessentities.VmTemplate; import org.ovirt.engine.core.common.businessentities.VolumeFormat; import org.ovirt.engine.core.common.queries.DiskImageList; import org.ovirt.engine.core.common.queries.GetAllFromExportDomainQueryParamenters; import org.ovirt.engine.core.common.queries.VdcQueryReturnValue; import org.ovirt.engine.core.common.queries.VdcQueryType; 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.compat.LogCompat; import org.ovirt.engine.core.compat.LogFactoryCompat; import org.ovirt.engine.core.compat.RefObject; import org.ovirt.engine.core.compat.StringHelper; import org.ovirt.engine.core.dal.VdcBllMessages; import org.ovirt.engine.core.dal.dbbroker.DbFacade; import org.ovirt.engine.core.utils.linq.Function; import org.ovirt.engine.core.utils.linq.LinqUtils; import org.ovirt.engine.core.utils.linq.Predicate; import org.ovirt.engine.core.utils.ovf.OvfManager; import org.ovirt.engine.core.utils.transaction.TransactionMethod; import org.ovirt.engine.core.utils.transaction.TransactionSupport; @NonTransactiveCommandAttribute(forceCompensation = true) public class ExportVmCommand<T extends MoveVmParameters> extends MoveOrCopyTemplateCommand<T> { /** * Constructor for command creation when compensation is applied on startup * * @param commandId */ protected ExportVmCommand(Guid commandId) { super(commandId); } public ExportVmCommand(T parameters) { super(parameters); setVmId(parameters.getContainerId()); parameters.setEntityId(getVmId()); setStoragePoolId(getVm().getstorage_pool_id()); } @Override protected boolean canDoAction() { boolean retVal = true; if (getVm() == null) { retVal = false; addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_VM_NOT_FOUND); } else { setDescription(getVmName()); } // check that target domain exists if (retVal) { retVal = ImportExportCommon.CheckStorageDomain(getParameters().getStorageDomainId(), getReturnValue() .getCanDoActionMessages()); } // load the disks of vm from database VmHandler.updateDisksFromDb(getVm()); // update vm snapshots for storage free space check for (DiskImage diskImage : getVm().getDiskMap().values()) { diskImage.getSnapshots().addAll( ImagesHandler.getAllImageSnapshots(diskImage.getId(), diskImage.getit_guid())); } setStoragePoolId(getVm().getstorage_pool_id()); // check that the target and source domain are in the same storage_pool if (DbFacade.getInstance() .getStoragePoolIsoMapDAO() .get(new StoragePoolIsoMapId(getStorageDomain().getid(), getVm().getstorage_pool_id())) == null) { retVal = false; addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_STORAGE_POOL_NOT_MATCH); } // check if template exists only if asked for if (retVal && getParameters().getTemplateMustExists()) { retVal = CheckTemplateInStorageDomain(getVm().getstorage_pool_id(), getParameters().getStorageDomainId(), getVm().getvmt_guid()); if (!retVal) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_TEMPLATE_NOT_FOUND_ON_EXPORT_DOMAIN); getReturnValue().getCanDoActionMessages().add( String.format("$TemplateName %1$s", getVm().getvmt_name())); } } // check if Vm has disks if (retVal && getVm().getDiskMap().size() <= 0) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_VM_HAS_NO_DISKS); retVal = false; } if (retVal) { Map<String, ? extends DiskImageBase> images = getParameters().getDiskInfoList(); if (images == null) { images = getVm().getDiskMap(); } // check that the images requested format are valid (COW+Sparse) retVal = ImagesHandler.CheckImagesConfiguration(getParameters().getStorageDomainId(), new java.util.ArrayList<DiskImageBase>(images.values()), getReturnValue().getCanDoActionMessages()); if (retVal && getParameters().getCopyCollapse()) { for (DiskImage img : getVm().getDiskMap().values()) { if (images.containsKey(img.getinternal_drive_mapping())) { // check that no RAW format exists (we are in collapse // mode) if (images.get(img.getinternal_drive_mapping()).getvolume_format() == VolumeFormat.RAW && img.getvolume_format() != VolumeFormat.RAW) { addCanDoActionMessage(VdcBllMessages.VM_CANNOT_EXPORT_RAW_FORMAT); retVal = false; } } } } } // check destination storage is active if (retVal) { retVal = IsDomainActive(getStorageDomain().getid(), getVm().getstorage_pool_id()); } // check destination storage is Export domain if (retVal) { if (getStorageDomain().getstorage_domain_type() != StorageDomainType.ImportExport) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_SPECIFY_DOMAIN_IS_NOT_EXPORT_DOMAIN); retVal = false; } } // check destination storage have free space if (retVal) { int sizeInGB = (int) getVm().getActualDiskWithSnapshotsSize(); retVal = StorageDomainSpaceChecker.hasSpaceForRequest(getStorageDomain(), sizeInGB); if (!retVal) addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_DISK_SPACE_LOW); } // Set source domain if (retVal) { // DiskImage image = null; //LINQ Vm.DiskMap.First().Value; DiskImage image = LinqUtils.first(getVm().getDiskMap().values()); if (image == null) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_VM_HAS_NO_DISKS); retVal = false; } if (retVal) { SetSourceDomainId(image.getstorage_id().getValue()); if (getSourceDomain() == null) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_STORAGE_DOMAIN_NOT_EXIST); retVal = false; } } } // check soource domain is active if (retVal) { retVal = IsDomainActive(getSourceDomain().getid(), getVm().getstorage_pool_id()); } // check that source domain is not ISO or Export domain if (retVal) { if (getSourceDomain().getstorage_domain_type() == StorageDomainType.ISO || getSourceDomain().getstorage_domain_type() == StorageDomainType.ImportExport) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_STORAGE_DOMAIN_TYPE_ILLEGAL); retVal = false; } } // check if Vm exists in export domain if (retVal) { retVal = CheckVmInStorageDomain(); } if (retVal) { // check that vm is down and images are ok retVal = retVal && ImagesHandler.PerformImagesChecks(getVmId(), getReturnValue().getCanDoActionMessages(), getVm() .getstorage_pool_id(), Guid.Empty, false, true, false, false, true, true, false); } if (!retVal) { addCanDoActionMessage(VdcBllMessages.VAR__ACTION__EXPORT); addCanDoActionMessage(VdcBllMessages.VAR__TYPE__VM); } return retVal; } @Override protected void executeCommand() { VmHandler.checkStatusAndLockVm(getVm().getvm_guid(), getCompensationContext()); TransactionSupport.executeInNewTransaction(new TransactionMethod<Void>() { @Override public Void runInTransaction() { MoveOrCopyAllImageGroups(); return null; } }); if (!getReturnValue().getTaskIdList().isEmpty()) { setSucceeded(true); } } public boolean UpdateCopyVmInSpm(Guid storagePoolId, java.util.ArrayList<VM> vmsList, Guid storageDomainId) { java.util.HashMap<Guid, KeyValuePairCompat<String, List<Guid>>> vmsAndMetaDictionary = new java.util.HashMap<Guid, KeyValuePairCompat<String, List<Guid>>>( vmsList.size()); OvfManager ovfManager = new OvfManager(); for (VM vm : vmsList) { java.util.ArrayList<DiskImage> AllVmImages = new java.util.ArrayList<DiskImage>(); VmHandler.updateDisksFromDb(vm); if (vm.getInterfaces() == null) { // TODO remove this when the API changes vm.getInterfaces().clear(); for(VmNetworkInterface iface: DbFacade.getInstance().getVmNetworkInterfaceDAO() .getAllForVm(vm.getvm_guid())) { vm.getInterfaces().add(iface); } } for (DiskImage disk : vm.getDiskMap().values()) { disk.setParentId(VmTemplateHandler.BlankVmTemplateId); disk.setit_guid(VmTemplateHandler.BlankVmTemplateId); disk.setstorage_id(storageDomainId); DiskImage diskForVolumeInfo = getDiskForVolumeInfo(disk); disk.setvolume_format(diskForVolumeInfo.getvolume_format()); disk.setvolume_type(diskForVolumeInfo.getvolume_type()); VDSReturnValue vdsReturnValue = Backend .getInstance() .getResourceManager() .RunVdsCommand( VDSCommandType.GetImageInfo, new GetImageInfoVDSCommandParameters(storagePoolId, storageDomainId, disk .getimage_group_id().getValue(), disk.getId())); if (vdsReturnValue != null && vdsReturnValue.getSucceeded()) { DiskImage fromVdsm = (DiskImage) vdsReturnValue.getReturnValue(); disk.setactual_size(fromVdsm.getactual_size()); } AllVmImages.add(disk); } if (StringHelper.isNullOrEmpty(vm.getvmt_name())) { VmTemplate t = DbFacade.getInstance().getVmTemplateDAO() .get(vm.getvmt_guid()); vm.setvmt_name(t.getname()); } getVm().setvmt_guid(VmTemplateHandler.BlankVmTemplateId); String vmMeta = null; RefObject<String> tempRefObject = new RefObject<String>(vmMeta); ovfManager.ExportVm(tempRefObject, vm, AllVmImages); vmMeta = tempRefObject.argvalue; // LINQ vmsAndMetaDictionary.Add(vm.vm_guid, new // KeyValuePair<string,List<Guid>> // LINQ (vmMeta, vm.DiskMap.Values.Select(a => // a.image_group_id.Value).ToList())); List<Guid> imageGroupIds = LinqUtils.foreach(vm.getDiskMap().values(), new Function<DiskImage, Guid>() { @Override public Guid eval(DiskImage diskImage) { return diskImage.getimage_group_id().getValue(); } }); vmsAndMetaDictionary .put(vm.getvm_guid(), new KeyValuePairCompat<String, List<Guid>>(vmMeta, imageGroupIds)); } UpdateVMVDSCommandParameters tempVar = new UpdateVMVDSCommandParameters(storagePoolId, vmsAndMetaDictionary); tempVar.setStorageDomainId(storageDomainId); return Backend.getInstance().getResourceManager().RunVdsCommand(VDSCommandType.UpdateVM, tempVar) .getSucceeded(); } @Override protected void MoveOrCopyAllImageGroups() { MoveOrCopyAllImageGroups(getVm().getvm_guid(), getVm().getDiskMap().values()); } @Override protected void MoveOrCopyAllImageGroups(Guid containerID, Iterable<DiskImage> disks) { for (DiskImage disk : disks) { MoveOrCopyImageGroupParameters tempVar = new MoveOrCopyImageGroupParameters(containerID, disk .getimage_group_id().getValue(), disk.getId(), getParameters().getStorageDomainId(), getMoveOrCopyImageOperation()); tempVar.setParentCommand(getActionType()); tempVar.setEntityId(getParameters().getEntityId()); tempVar.setUseCopyCollapse(getParameters().getCopyCollapse()); DiskImage diskForVolumeInfo = getDiskForVolumeInfo(disk); tempVar.setVolumeFormat(diskForVolumeInfo.getvolume_format()); tempVar.setVolumeType(diskForVolumeInfo.getvolume_type()); tempVar.setCopyVolumeType(CopyVolumeType.LeafVol); tempVar.setPostZero(disk.getwipe_after_delete()); tempVar.setForceOverride(getParameters().getForceOverride()); MoveOrCopyImageGroupParameters p = tempVar; p.setParentParemeters(getParameters()); VdcReturnValueBase vdcRetValue = Backend.getInstance().runInternalAction( VdcActionType.MoveOrCopyImageGroup, p); getParameters().getImagesParameters().add(p); getReturnValue().getTaskIdList().addAll(vdcRetValue.getInternalTaskIdList()); } } /** * 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()) { DiskImage ancestor = DbFacade.getInstance().getDiskImageDAO().getAncestor(disk.getId()); if (ancestor == null) { log.warnFormat("Can't find ancestor of Disk with ID {0}, using original disk for volume info.", disk.getId()); ancestor = disk; } return ancestor; } else { return disk; } } protected boolean CheckVmInStorageDomain() { boolean retVal = true; GetAllFromExportDomainQueryParamenters tempVar = new GetAllFromExportDomainQueryParamenters(getVm() .getstorage_pool_id(), getParameters().getStorageDomainId()); tempVar.setGetAll(true); VdcQueryReturnValue qretVal = Backend.getInstance().runInternalQuery(VdcQueryType.GetVmsFromExportDomain, tempVar); if (qretVal.getSucceeded()) { java.util.ArrayList<VM> vms = (java.util.ArrayList<VM>) qretVal.getReturnValue(); for (VM vm : vms) { // check the same id when not overriding if (vm.getvm_guid().equals(getVm().getvm_guid()) && !getParameters().getForceOverride()) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_VM_GUID_ALREADY_EXIST); retVal = false; break; // check the same name when not overriding } else if (vm.getvm_name().equals(getVm().getvm_name()) && !getParameters().getForceOverride()) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_VM_ALREADY_EXIST); retVal = false; break; // check if we have vm with the same name and overriding } else if (!vm.getvm_guid().equals(getVm().getvm_guid()) && vm.getvm_name().equals(getVm().getvm_name())) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_VM_ALREADY_EXIST); retVal = false; break; } // check if we have vm with the same id and overriding else if (vm.getvm_guid().equals(getVm().getvm_guid()) && !vm.getvm_name().equals(getVm().getvm_name())) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_VM_GUID_ALREADY_EXIST); retVal = false; break; } } } return retVal; } public static boolean CheckTemplateInStorageDomain(Guid storagePoolId, Guid storageDomainId, final Guid tmplId) { boolean retVal = false; GetAllFromExportDomainQueryParamenters tempVar = new GetAllFromExportDomainQueryParamenters(storagePoolId, storageDomainId); tempVar.setGetAll(true); VdcQueryReturnValue qretVal = Backend.getInstance().runInternalQuery(VdcQueryType.GetTemplatesFromExportDomain, tempVar); if (qretVal.getSucceeded()) { if (!VmTemplateHandler.BlankVmTemplateId.equals(tmplId)) { Map<VmTemplate, DiskImageList> templates = (Map) qretVal.getReturnValue(); // LINQ VAR var tmpl = templates.FirstOrDefault(t => // t.Key.vmt_guid == tmplId); VmTemplate tmpl = LinqUtils.firstOrNull(templates.keySet(), new Predicate<VmTemplate>() { @Override public boolean eval(VmTemplate vmTemplate) { return vmTemplate.getId().equals(tmplId); } }); // retVal = false; //LINQ VAR (tmpl.Key != null); retVal = tmpl != null; } 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; case END_FAILURE: return AuditLogType.IMPORTEXPORT_EXPORT_VM_FAILED; } return super.getAuditLogTypeValue(); } protected boolean UpdateVmImSpm() { return VmCommand.UpdateVmInSpm(getVm().getstorage_pool_id(), new java.util.ArrayList<VM>(java.util.Arrays.asList(new VM[] { getVm() })), getParameters() .getStorageDomainId()); } @Override protected void EndSuccessfully() { EndActionOnAllImageGroups(); if (getVm() != null) { VmHandler.UnLockVm(getVm().getvm_guid()); VmHandler.updateDisksFromDb(getVm()); if (getParameters().getCopyCollapse()) { VM vm = getVm(); vm.setvmt_guid(VmTemplateHandler.BlankVmTemplateId); vm.setvmt_name(null); UpdateCopyVmInSpm(getVm().getstorage_pool_id(), new java.util.ArrayList<VM>(java.util.Arrays.asList(new VM[] { vm })), getParameters() .getStorageDomainId()); } else { UpdateVmImSpm(); } } else { setCommandShouldBeLogged(false); log.warn("ExportVmCommand::EndMoveVmCommand: Vm is null - not performing full EndAction"); } setSucceeded(true); } @Override protected void EndWithFailure() { EndActionOnAllImageGroups(); if (getVm() != null) { VmHandler.UnLockVm(getVm().getvm_guid()); VmHandler.updateDisksFromDb(getVm()); } else { setCommandShouldBeLogged(false); log.warn("ExportVmCommand::EndMoveVmCommand: Vm is null - not performing full EndAction"); } setSucceeded(true); } private static LogCompat log = LogFactoryCompat.getLog(ExportVmCommand.class); }