package org.ovirt.engine.core.utils.ovf; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import javax.inject.Inject; import javax.inject.Singleton; import org.ovirt.engine.core.bll.CpuFlagsManagerHandler; import org.ovirt.engine.core.common.businessentities.Cluster; import org.ovirt.engine.core.common.businessentities.VM; import org.ovirt.engine.core.common.businessentities.VmBase; import org.ovirt.engine.core.common.businessentities.VmDevice; import org.ovirt.engine.core.common.businessentities.VmDeviceId; 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.DiskImage; import org.ovirt.engine.core.common.businessentities.storage.DiskVmElement; import org.ovirt.engine.core.common.osinfo.OsRepository; import org.ovirt.engine.core.common.queries.VmIconIdSizePair; import org.ovirt.engine.core.common.utils.VmDeviceCommonUtils; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.compat.Version; import org.ovirt.engine.core.dao.ClusterDao; import org.ovirt.engine.core.dao.DiskVmElementDao; import org.ovirt.engine.core.dao.network.VmNetworkInterfaceDao; import org.ovirt.engine.core.utils.ovf.xml.XmlDocument; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Singleton public class OvfManager { private Logger log = LoggerFactory.getLogger(OvfManager.class); @Inject private OvfVmIconDefaultsProvider iconDefaultsProvider; @Inject private ClusterDao clusterDao; @Inject private DiskVmElementDao diskVmElementDao; @Inject private VmNetworkInterfaceDao vmNetworkInterfaceDao; @Inject private CpuFlagsManagerHandler cpuFlagsManagerHandler; public String exportVm(VM vm, List<DiskImage> images, Version version) { updateBootOrderOnDevices(vm.getStaticData(), false); final OvfVmWriter vmWriter; if (vm.isHostedEngine()) { Cluster cluster = clusterDao.get(vm.getClusterId()); String cpuId = cpuFlagsManagerHandler.getCpuId(cluster.getCpuName(), cluster.getCompatibilityVersion()); vmWriter = new HostedEngineOvfWriter(vm, images, version, cluster.getEmulatedMachine(), cpuId); } else { vmWriter = new OvfVmWriter(vm, images, version); } return vmWriter.build().getStringRepresentation(); } public String exportTemplate(VmTemplate vmTemplate, List<DiskImage> images, Version version) { updateBootOrderOnDevices(vmTemplate, true); return new OvfTemplateWriter(vmTemplate, images, version).build().getStringRepresentation(); } public void importVm(String ovfstring, VM vm, List<DiskImage> images, List<VmNetworkInterface> interfaces) throws OvfReaderException { OvfReader ovf = null; try { ovf = new OvfVmReader(new XmlDocument(ovfstring), vm, images, interfaces); ovf.build(); initIcons(vm.getStaticData()); } catch (Exception ex) { String message = generateOvfReaderErrorMessage(ovf, ex); logOvfLoadError(message, ovfstring); throw new OvfReaderException(message); } Guid id = vm.getStaticData().getId(); for (VmNetworkInterface iface : interfaces) { iface.setVmId(id); } } public void importTemplate(String ovfstring, VmTemplate vmTemplate, List<DiskImage> images, List<VmNetworkInterface> interfaces) throws OvfReaderException { OvfReader ovf = null; try { ovf = new OvfTemplateReader(new XmlDocument(ovfstring), vmTemplate, images, interfaces); ovf.build(); initIcons(vmTemplate); } catch (Exception ex) { String message = generateOvfReaderErrorMessage(ovf, ex); logOvfLoadError(message, ovfstring); throw new OvfReaderException(message); } } private String generateOvfReaderErrorMessage(OvfReader ovf, Exception ex) { StringBuilder message = new StringBuilder(); if (ovf == null) { message.append("Error loading ovf, message") .append(ex.getMessage()); } else { message.append("OVF error: ") .append(ovf.getName()) .append(": cannot read '") .append(ovf.getLastReadEntry()) .append("' with value: ") .append(ex.getMessage()); } return message.toString(); } private void initIcons(VmBase vmBase) { final int osId = vmBase.getOsId(); final int fallbackOsId = OsRepository.DEFAULT_X86_OS; final Map<Integer, VmIconIdSizePair> vmIconDefaults = iconDefaultsProvider.getVmIconDefaults(); final VmIconIdSizePair iconPair = vmIconDefaults.containsKey(osId) ? vmIconDefaults.get(osId) : vmIconDefaults.get(fallbackOsId); vmBase.setSmallIconId(iconPair.getSmall()); vmBase.setLargeIconId(iconPair.getLarge()); } private void logOvfLoadError(String message, String ovfstring) { log.error("Error parsing OVF due to {}", message); log.debug("Error parsing OVF {}\n", ovfstring); } public boolean isOvfTemplate(String ovfstring) throws OvfReaderException { return new OvfParser(ovfstring).isTemplate(); } /** * For backward compatibility we need to set the boot order on each device * in the OVF. This can be dropped as soon as we drop support for 4.0. * Note that this method is made public for visibility for tests outside of its package. */ public void updateBootOrderOnDevices(VmBase vmBase, boolean template) { Collection<VmDevice> devices = vmBase.getManagedDeviceMap().values(); // Reset current boot order devices.forEach(device -> device.setBootOrder(0)); Map<VmDeviceId, DiskVmElement> diskVmElements = diskVmElementDao.getAllForVm(vmBase.getId()) .stream() .collect(Collectors.toMap(DiskVmElement::getId, element -> element)); List<VmNetworkInterface> interfaces = template ? vmNetworkInterfaceDao.getAllForTemplate(vmBase.getId()) : vmNetworkInterfaceDao.getAllForVm(vmBase.getId()); VmDeviceCommonUtils.updateVmDevicesBootOrder( vmBase.getDefaultBootSequence(), devices, interfaces, diskVmElements); } }