package org.ovirt.engine.core.utils.ovf; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.ovirt.engine.core.common.businessentities.BootSequence; import org.ovirt.engine.core.common.businessentities.DisplayType; import org.ovirt.engine.core.common.businessentities.GraphicsDevice; import org.ovirt.engine.core.common.businessentities.GraphicsType; import org.ovirt.engine.core.common.businessentities.MigrationSupport; import org.ovirt.engine.core.common.businessentities.OriginType; import org.ovirt.engine.core.common.businessentities.SerialNumberPolicy; import org.ovirt.engine.core.common.businessentities.SsoMethod; import org.ovirt.engine.core.common.businessentities.UsbPolicy; import org.ovirt.engine.core.common.businessentities.VmBase; import org.ovirt.engine.core.common.businessentities.VmDevice; import org.ovirt.engine.core.common.businessentities.VmDeviceGeneralType; import org.ovirt.engine.core.common.businessentities.VmDeviceId; import org.ovirt.engine.core.common.businessentities.VmInit; import org.ovirt.engine.core.common.businessentities.VmType; import org.ovirt.engine.core.common.businessentities.network.VmInterfaceType; import org.ovirt.engine.core.common.businessentities.network.VmNetworkInterface; import org.ovirt.engine.core.common.businessentities.storage.CinderDisk; import org.ovirt.engine.core.common.businessentities.storage.DiskImage; import org.ovirt.engine.core.common.businessentities.storage.DiskInterface; import org.ovirt.engine.core.common.businessentities.storage.DiskStorageType; import org.ovirt.engine.core.common.businessentities.storage.DiskVmElement; import org.ovirt.engine.core.common.businessentities.storage.ImageStatus; import org.ovirt.engine.core.common.businessentities.storage.VolumeFormat; import org.ovirt.engine.core.common.businessentities.storage.VolumeType; import org.ovirt.engine.core.common.config.Config; import org.ovirt.engine.core.common.config.ConfigValues; import org.ovirt.engine.core.common.osinfo.OsRepository; import org.ovirt.engine.core.common.utils.Pair; import org.ovirt.engine.core.common.utils.SimpleDependencyInjector; import org.ovirt.engine.core.common.utils.VmDeviceCommonUtils; import org.ovirt.engine.core.common.utils.VmDeviceType; import org.ovirt.engine.core.common.utils.customprop.VmPropertiesUtils; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.compat.Version; import org.ovirt.engine.core.utils.VmInitUtils; import org.ovirt.engine.core.utils.customprop.DevicePropertiesUtils; import org.ovirt.engine.core.utils.ovf.xml.XmlDocument; import org.ovirt.engine.core.utils.ovf.xml.XmlNamespaceManager; import org.ovirt.engine.core.utils.ovf.xml.XmlNode; import org.ovirt.engine.core.utils.ovf.xml.XmlNodeList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public abstract class OvfReader implements IOvfBuilder { private static final Logger log = LoggerFactory.getLogger(OvfReader.class); protected OsRepository osRepository = SimpleDependencyInjector.getInstance().get(OsRepository.class); protected List<DiskImage> _images; protected List<VmNetworkInterface> interfaces; protected XmlDocument _document; protected XmlNamespaceManager _xmlNS; private static final int BYTES_IN_GB = 1024 * 1024 * 1024; public static final String EmptyName = "[Empty Name]"; protected String name = EmptyName; private String version; private final VmBase vmBase; private String lastReadEntry = ""; public OvfReader(XmlDocument document, List<DiskImage> images, List<VmNetworkInterface> interfaces, VmBase vmBase) { _images = images; this.interfaces = interfaces; _document = document; this.vmBase = vmBase; _xmlNS = new XmlNamespaceManager(); _xmlNS.addNamespace("ovf", OVF_URI); _xmlNS.addNamespace("rasd", RASD_URI); _xmlNS.addNamespace("vssd", VSSD_URI); _xmlNS.addNamespace("xsi", XSI_URI); readHeader(); } public String getName() { return name; } public String getVersion() { return version; } /** * reads the OVF header */ private void readHeader() { version = ""; XmlNode node = selectSingleNode(_document, "//ovf:Envelope", _xmlNS); if (node != null) { version = node.attributes.get("ovf:version").getValue(); } } @Override public void buildReference() { buildImageReference(); buildNicReference(); } @Override public void buildNetwork() { // No implementation - networks aren't read from the OVF. } protected long convertGigabyteToBytes(long gb) { return gb * BYTES_IN_GB; } @Override public void buildDisk() { XmlNodeList list = selectNodes(_document, "//*/Section/Disk"); for (XmlNode node : list) { final Guid guid = new Guid(node.attributes.get("ovf:diskId").getValue()); DiskImage image = _images.stream().filter(d -> d.getImageId().equals(guid)).findFirst().orElse(null); DiskVmElement dve = image.getDiskVmElementForVm(vmBase.getId()); if (node.attributes.get("ovf:vm_snapshot_id") != null) { image.setVmSnapshotId(new Guid(node.attributes.get("ovf:vm_snapshot_id").getValue())); } if (!StringUtils.isEmpty(node.attributes.get("ovf:size").getValue())) { image.setSize(convertGigabyteToBytes(Long.parseLong(node.attributes.get("ovf:size").getValue()))); } if (!StringUtils.isEmpty(node.attributes.get("ovf:actual_size").getValue())) { image.setActualSizeInBytes(convertGigabyteToBytes(Long.parseLong(node.attributes.get("ovf:actual_size").getValue()))); } if (node.attributes.get("ovf:volume-format") != null) { if (!StringUtils.isEmpty(node.attributes.get("ovf:volume-format").getValue())) { image.setVolumeFormat(VolumeFormat.valueOf(node.attributes.get("ovf:volume-format").getValue())); } else { image.setVolumeFormat(VolumeFormat.Unassigned); } } else { image.setVolumeFormat(VolumeFormat.Unassigned); } if (node.attributes.get("ovf:volume-type") != null) { if (!StringUtils.isEmpty(node.attributes.get("ovf:volume-type").getValue())) { image.setVolumeType(VolumeType.valueOf(node.attributes.get("ovf:volume-type").getValue())); } else { image.setVolumeType(VolumeType.Unassigned); } } else { image.setVolumeType(VolumeType.Unassigned); } if (node.attributes.get("ovf:disk-interface") != null) { if (!StringUtils.isEmpty(node.attributes.get("ovf:disk-interface").getValue())) { dve.setDiskInterface(DiskInterface.valueOf(node.attributes.get("ovf:disk-interface").getValue())); } } else { dve.setDiskInterface(DiskInterface.IDE); } if (node.attributes.get("ovf:boot") != null) { if (!StringUtils.isEmpty(node.attributes.get("ovf:boot").getValue())) { dve.setBoot(Boolean.parseBoolean(node.attributes.get("ovf:boot").getValue())); } } if (node.attributes.get("ovf:pass-discard") != null) { if (!StringUtils.isEmpty(node.attributes.get("ovf:pass-discard").getValue())) { dve.setPassDiscard(Boolean.parseBoolean(node.attributes.get("ovf:pass-discard").getValue())); } } if (node.attributes.get("ovf:wipe-after-delete") != null) { if (!StringUtils.isEmpty(node.attributes.get("ovf:wipe-after-delete").getValue())) { image.setWipeAfterDelete(Boolean.parseBoolean(node.attributes.get("ovf:wipe-after-delete") .getValue())); } } if (node.attributes.get("ovf:disk-alias") != null) { if (!StringUtils.isEmpty(node.attributes.get("ovf:disk-alias").getValue())) { image.setDiskAlias(String.valueOf(node.attributes.get("ovf:disk-alias") .getValue())); } } if (node.attributes.get("ovf:disk-description") != null) { if (!StringUtils.isEmpty(node.attributes.get("ovf:disk-description").getValue())) { image.setDiskDescription(String.valueOf(node.attributes.get("ovf:disk-description") .getValue())); } } } } @Override public void buildVirtualSystem() { readGeneralData(); } protected VmDevice readManagedVmDevice(XmlNode node, Guid deviceId) { return addManagedVmDevice(readVmDevice(node, deviceId)); } private VmDevice addManagedVmDevice(VmDevice vmDevice) { vmDevice.setManaged(true); vmBase.getManagedDeviceMap().put(vmDevice.getDeviceId(), vmDevice); return vmDevice; } protected VmDevice readUnmanagedVmDevice(XmlNode node, Guid deviceId) { VmDevice vmDevice = readVmDevice(node, deviceId); vmBase.getUnmanagedDeviceList().add(vmDevice); return vmDevice; } /** * Reads vm device attributes from OVF and stores it in the collection */ private VmDevice readVmDevice(XmlNode node, Guid deviceId) { VmDevice vmDevice = new VmDevice(); vmDevice.setId(new VmDeviceId(deviceId, vmBase.getId())); if (selectSingleNode(node, OvfProperties.VMD_ADDRESS, _xmlNS) != null && !StringUtils.isEmpty(selectSingleNode(node, OvfProperties.VMD_ADDRESS, _xmlNS).innerText)) { vmDevice.setAddress(String.valueOf(selectSingleNode(node, OvfProperties.VMD_ADDRESS, _xmlNS).innerText)); } else { vmDevice.setAddress(""); } if (selectSingleNode(node, OvfProperties.VMD_ALIAS, _xmlNS) != null && !StringUtils.isEmpty(selectSingleNode(node, OvfProperties.VMD_ALIAS, _xmlNS).innerText)) { vmDevice.setAlias(String.valueOf(selectSingleNode(node, OvfProperties.VMD_ALIAS, _xmlNS).innerText)); } else { vmDevice.setAlias(""); } XmlNode specParamsNode = selectSingleNode(node, OvfProperties.VMD_SPEC_PARAMS, _xmlNS); if (specParamsNode != null && !StringUtils.isEmpty(specParamsNode.innerText)) { vmDevice.setSpecParams(getMapNode(specParamsNode)); } else { // Empty map vmDevice.setSpecParams(Collections.emptyMap()); } if (selectSingleNode(node, OvfProperties.VMD_TYPE, _xmlNS) != null && !StringUtils.isEmpty(selectSingleNode(node, OvfProperties.VMD_TYPE, _xmlNS).innerText)) { vmDevice.setType(VmDeviceGeneralType.forValue(String.valueOf(selectSingleNode(node, OvfProperties.VMD_TYPE, _xmlNS).innerText))); } else { int resourceType = getResourceType(node, OvfProperties.VMD_RESOURCE_TYPE); vmDevice.setType(VmDeviceGeneralType.forValue(VmDeviceType.getoVirtDevice(resourceType))); } if (selectSingleNode(node, OvfProperties.VMD_DEVICE, _xmlNS) != null && !StringUtils.isEmpty(selectSingleNode(node, OvfProperties.VMD_DEVICE, _xmlNS).innerText)) { vmDevice.setDevice(String.valueOf(selectSingleNode(node, OvfProperties.VMD_DEVICE, _xmlNS).innerText)); } else { setDeviceByResource(node, vmDevice); } if (selectSingleNode(node, OvfProperties.VMD_IS_PLUGGED, _xmlNS) != null && !StringUtils.isEmpty(selectSingleNode(node, OvfProperties.VMD_IS_PLUGGED, _xmlNS).innerText)) { vmDevice.setPlugged(Boolean.valueOf(selectSingleNode(node, OvfProperties.VMD_IS_PLUGGED, _xmlNS).innerText)); } else { vmDevice.setPlugged(Boolean.TRUE); } if (selectSingleNode(node, OvfProperties.VMD_IS_READONLY, _xmlNS) != null && !StringUtils.isEmpty(selectSingleNode(node, OvfProperties.VMD_IS_READONLY, _xmlNS).innerText)) { vmDevice.setReadOnly(Boolean.valueOf(selectSingleNode(node, OvfProperties.VMD_IS_READONLY, _xmlNS).innerText)); } else { vmDevice.setReadOnly(Boolean.FALSE); } if (selectSingleNode(node, OvfProperties.VMD_CUSTOM_PROP, _xmlNS) != null && StringUtils.isNotEmpty(selectSingleNode(node, OvfProperties.VMD_CUSTOM_PROP, _xmlNS).innerText)) { vmDevice.setCustomProperties(DevicePropertiesUtils.getInstance().convertProperties( String.valueOf(selectSingleNode(node, OvfProperties.VMD_CUSTOM_PROP, _xmlNS).innerText))); } else { vmDevice.setCustomProperties(null); } if (selectSingleNode(node, OvfProperties.VMD_SNAPSHOT_PROP, _xmlNS) != null && StringUtils.isNotEmpty(selectSingleNode(node, OvfProperties.VMD_SNAPSHOT_PROP, _xmlNS).innerText)) { vmDevice.setSnapshotId(new Guid(String.valueOf(selectSingleNode(node, OvfProperties.VMD_CUSTOM_PROP, _xmlNS).innerText))); } return vmDevice; } /** * gets the VM interface * * @param node * the xml node * @return VmNetworkInterface */ public VmNetworkInterface getNetworkInterface(XmlNode node) { // prior to 3.0 the instanceId is int , in 3.1 and on this is Guid String str = selectSingleNode(node, "rasd:InstanceId", _xmlNS).innerText; if (!StringUtils.isNumeric(str)) { // 3.1 and above OVF format final Guid guid = new Guid(str); VmNetworkInterface iface = interfaces.stream().filter(i -> i.getId().equals(guid)).findFirst().orElse(null); if (iface == null) { iface = new VmNetworkInterface(); iface.setId(guid); } return iface; } else { // 3.0 and below OVF format return new VmNetworkInterface(); } } /** * This method should return the string representation of 'default display type' * property in the ovf file. this representation is different for ovf file * of VM and ovf file of template. * * @return the String representation of 'default display type' property in the ovf file */ protected abstract String getDefaultDisplayTypeStringRepresentation(); protected abstract void readOsSection(XmlNode section); protected void readHardwareSection(XmlNode section) { boolean readVirtioSerial = false; for (XmlNode node : selectNodes(section, "Item")) { switch (selectSingleNode(node, "rasd:ResourceType", _xmlNS).innerText) { case OvfHardware.CPU: readCpuItem(node); break; case OvfHardware.Memory: readMemoryItem(node); break; case OvfHardware.DiskImage: readDiskImageItem(node); break; case OvfHardware.Network: readNetworkItem(node); break; case OvfHardware.USB: readUsbItem(node); break; case OvfHardware.Monitor: readMonitorItem(node); break; case OvfHardware.Graphics: readManagedVmDevice(node, Guid.newGuid()); // so far graphics doesn't contain anything special break; case OvfHardware.CD: readCdItem(node); break; case OvfHardware.OTHER: VmDevice vmDevice = readOtherHardwareItem(node); readVirtioSerial = readVirtioSerial || VmDeviceType.VIRTIOSERIAL.getName().equals(vmDevice.getDevice()); break; } } if (!readVirtioSerial) { addManagedVmDevice(VmDeviceCommonUtils.createVirtioSerialDeviceForVm(vmBase.getId())); } } protected abstract void readDiskImageItem(XmlNode node); protected void readMonitorItem(XmlNode node) { vmBase.setNumOfMonitors( Integer.parseInt(selectSingleNode(node, "rasd:VirtualQuantity", _xmlNS).innerText)); if (selectSingleNode(node, "rasd:SinglePciQxl", _xmlNS) != null) { vmBase.setSingleQxlPci(Boolean.parseBoolean(selectSingleNode(node, "rasd:SinglePciQxl", _xmlNS).innerText)); } readManagedVmDevice(node, Guid.newGuid()); } protected Integer parseNodeInteger(XmlNode sourceNode, String string, Integer defaultValue) { XmlNode subNode = selectSingleNode(sourceNode, string, _xmlNS); if (subNode != null && subNode.innerText != null) { return Integer.parseInt(subNode.innerText); } return defaultValue; } private void readCpuItem(XmlNode node) { vmBase.setNumOfSockets( Integer.parseInt(selectSingleNode(node, "rasd:num_of_sockets", _xmlNS).innerText)); vmBase.setCpuPerSocket( Integer.parseInt(selectSingleNode(node, "rasd:cpu_per_socket", _xmlNS).innerText)); vmBase.setThreadsPerCpu(parseNodeInteger(node, "rasd:threads_per_cpu", 1)); } private void readMemoryItem(XmlNode node) { vmBase.setMemSizeMb( Integer.parseInt(selectSingleNode(node, "rasd:VirtualQuantity", _xmlNS).innerText)); } private void readCdItem(XmlNode node) { readManagedVmDevice(node, Guid.newGuid()); } private void readNetworkItem(XmlNode node) { VmNetworkInterface iface = getNetworkInterface(node); updateSingleNic(node, iface); vmBase.getInterfaces().add(iface); readManagedVmDevice(node, iface.getId()); } private void readUsbItem(XmlNode node) { vmBase.setUsbPolicy( UsbPolicy.forStringValue(selectSingleNode(node, "rasd:UsbPolicy", _xmlNS).innerText)); } private VmDevice readOtherHardwareItem(XmlNode node) { boolean managed = false; if (selectSingleNode(node, OvfProperties.VMD_TYPE, _xmlNS) != null && StringUtils.isNotEmpty(selectSingleNode(node, OvfProperties.VMD_TYPE, _xmlNS).innerText)) { VmDeviceGeneralType type = VmDeviceGeneralType.forValue(String.valueOf(selectSingleNode(node, OvfProperties.VMD_TYPE, _xmlNS).innerText)); String device = selectSingleNode(node, OvfProperties.VMD_DEVICE, _xmlNS).innerText; // special devices are treated as managed devices but still have the OTHER OVF ResourceType managed = VmDeviceCommonUtils.isSpecialDevice(device, type); } return managed ? readManagedVmDevice(node, Guid.newGuid()) : readUnmanagedVmDevice(node, Guid.newGuid()); } protected void readGeneralData() { XmlNode content = selectSingleNode(_document, "//*/Content"); XmlNode node; vmBase.setVmInit(new VmInit()); // set ovf version to the ovf object vmBase.setOvfVersion(getVersion()); node = selectSingleNode(content, OvfProperties.DESCRIPTION); if (node != null) { vmBase.setDescription(node.innerText); } node = selectSingleNode(content, OvfProperties.COMMENT); if (node != null) { vmBase.setComment(node.innerText); } node = selectSingleNode(content, OvfProperties.DOMAIN); if (node != null) { vmBase.getVmInit().setDomain(node.innerText); } node = selectSingleNode(content, OvfProperties.CREATION_DATE); if (node != null) { Date creationDate = OvfParser.utcDateStringToLocaDate(node.innerText); if (creationDate != null) { vmBase.setCreationDate(creationDate); } } node = selectSingleNode(content, OvfProperties.EXPORT_DATE); if (node != null) { Date exportDate = OvfParser.utcDateStringToLocaDate(node.innerText); if (exportDate != null) { vmBase.setExportDate(exportDate); } } node = selectSingleNode(content, OvfProperties.DEFAULT_BOOT_SEQUENCE); if (node != null) { if (!StringUtils.isEmpty(node.innerText)) { vmBase.setDefaultBootSequence(BootSequence.forValue(Integer.parseInt(node.innerText))); } } node = selectSingleNode(content, OvfProperties.INITRD_URL); if (node != null) { if (!StringUtils.isEmpty(node.innerText)) { vmBase.setInitrdUrl(node.innerText); } } node = selectSingleNode(content, OvfProperties.KERNEL_URL); if (node != null) { if (!StringUtils.isEmpty(node.innerText)) { vmBase.setKernelUrl(node.innerText); } } node = selectSingleNode(content, OvfProperties.KERNEL_PARAMS); if (node != null) { if (!StringUtils.isEmpty(node.innerText)) { vmBase.setKernelParams(node.innerText); } } node = selectSingleNode(content, OvfProperties.GENERATION); if (node != null) { vmBase.setDbGeneration(Long.parseLong(node.innerText)); } else { vmBase.setDbGeneration(1L); } node = selectSingleNode(content, OvfProperties.CUSTOM_COMPATIBILITY_VERSION); if (node != null) { vmBase.setCustomCompatibilityVersion(new Version(node.innerText)); } Version originVersion = new Version(getVersion()); // the originating ENGINE version node = selectSingleNode(content, OvfProperties.CLUSTER_COMPATIBILITY_VERSION); if (node != null) { originVersion = new Version(node.innerText); } vmBase.setClusterCompatibilityVersionOrigin(originVersion); // Note: the fetching of 'default display type' should happen before reading // the hardware section node = selectSingleNode(content, getDefaultDisplayTypeStringRepresentation()); if (node != null) { if (!StringUtils.isEmpty(node.innerText)) { vmBase.setDefaultDisplayType(DisplayType.forValue(Integer.parseInt(node.innerText))); } } XmlNodeList list = selectNodes(content, "Section"); if (list != null) { // The Os need to be read before the hardware node = getNode(list, "xsi:type", "ovf:OperatingSystemSection_Type"); if (node != null) { readOsSection(node); if (!osRepository.isLinux(vmBase.getOsId()) || vmBase.getDefaultDisplayType() != DisplayType.qxl) { vmBase.setSingleQxlPci(false); } } node = getNode(list, "xsi:type", "ovf:VirtualHardwareSection_Type"); if (node != null) { readHardwareSection(node); } node = getNode(list, "xsi:type", "ovf:SnapshotsSection_Type"); if (node != null) { readSnapshotsSection(node); } } // after reading the hardware section, if graphics device is still absent, add a default one addDefaultGraphicsDevice(); fixDiskVmElements(); // due to dependency on vmBase.getOsId() must be read AFTER readOsSection node = selectSingleNode(content, OvfProperties.TIMEZONE); if (node != null && StringUtils.isNotEmpty(node.innerText)) { vmBase.setTimeZone(node.innerText); } else { if (osRepository.isWindows(vmBase.getOsId())) { vmBase.setTimeZone(Config.getValue(ConfigValues.DefaultWindowsTimeZone)); } else { vmBase.setTimeZone(Config.getValue(ConfigValues.DefaultGeneralTimeZone)); } } node = selectSingleNode(content, OvfProperties.ORIGIN); if (node != null) { if (!StringUtils.isEmpty(node.innerText)) { vmBase.setOrigin(OriginType.forValue(Integer.parseInt(node.innerText))); } } node = selectSingleNode(content, OvfProperties.VM_TYPE); if (node != null) { if (!StringUtils.isEmpty(node.innerText)) { vmBase.setVmType(VmType.forValue(Integer.parseInt(node.innerText))); } } node = selectSingleNode(content, OvfProperties.IS_SMARTCARD_ENABLED); if (node != null) { if (!StringUtils.isEmpty(node.innerText)) { vmBase.setSmartcardEnabled(Boolean.parseBoolean(node.innerText)); } } node = selectSingleNode(content, OvfProperties.NUM_OF_IOTHREADS); if (node != null) { if (!StringUtils.isEmpty(node.innerText)) { vmBase.setNumOfIoThreads(Integer.parseInt(node.innerText)); } } node = selectSingleNode(content, OvfProperties.DELETE_PROTECTED); if (node != null) { if (!StringUtils.isEmpty(node.innerText)) { vmBase.setDeleteProtected(Boolean.parseBoolean(node.innerText)); } } node = selectSingleNode(content, OvfProperties.SSO_METHOD); if (node != null) { if (!StringUtils.isEmpty(node.innerText)) { vmBase.setSsoMethod(SsoMethod.fromString(node.innerText)); } } node = selectSingleNode(content, OvfProperties.TUNNEL_MIGRATION); if (node != null) { if (!StringUtils.isEmpty(node.innerText)) { vmBase.setTunnelMigration(Boolean.parseBoolean(node.innerText)); } } node = selectSingleNode(content, OvfProperties.VNC_KEYBOARD_LAYOUT); if (node != null) { if (!StringUtils.isEmpty(node.innerText)) { vmBase.setVncKeyboardLayout(node.innerText); } } node = selectSingleNode(content, OvfProperties.MIN_ALLOCATED_MEMORY); if (node != null) { if (StringUtils.isNotEmpty(node.innerText)) { vmBase.setMinAllocatedMem(Integer.parseInt(node.innerText)); } } node = selectSingleNode(content, OvfProperties.IS_STATELESS); if (node != null) { if (StringUtils.isNotEmpty(node.innerText)) { vmBase.setStateless(Boolean.parseBoolean(node.innerText)); } } node = selectSingleNode(content, OvfProperties.IS_RUN_AND_PAUSE); if (node != null) { if (StringUtils.isNotEmpty(node.innerText)) { vmBase.setRunAndPause(Boolean.parseBoolean(node.innerText)); } } node = selectSingleNode(content, OvfProperties.CREATED_BY_USER_ID); if (node != null) { if (StringUtils.isNotEmpty(node.innerText)) { vmBase.setCreatedByUserId(Guid.createGuidFromString(node.innerText)); } } node = selectSingleNode(content, OvfProperties.MIGRATION_DOWNTIME); if (node != null) { if (StringUtils.isNotEmpty(node.innerText)) { vmBase.setMigrationDowntime(Integer.parseInt(node.innerText)); } } node = selectSingleNode(content, OvfProperties.MIGRATION_SUPPORT); if (node != null) { if (StringUtils.isNotEmpty(node.innerText)) { MigrationSupport migrationSupport = MigrationSupport.forValue(Integer.parseInt(node.innerText)); vmBase.setMigrationSupport(migrationSupport); } } // TODO dedicated to multiple hosts readDedicatedHostsList(); node = selectSingleNode(content, OvfProperties.SERIAL_NUMBER_POLICY); if (node != null) { if (StringUtils.isNotEmpty(node.innerText)) { vmBase.setSerialNumberPolicy(SerialNumberPolicy.forValue(Integer.parseInt(node.innerText))); } } node = selectSingleNode(content, OvfProperties.CUSTOM_SERIAL_NUMBER); if (node != null) { if (StringUtils.isNotEmpty(node.innerText)) { vmBase.setCustomSerialNumber(node.innerText); } } node = selectSingleNode(content, OvfProperties.AUTO_STARTUP); if (node != null) { vmBase.setAutoStartup(Boolean.parseBoolean(node.innerText)); } node = selectSingleNode(content, OvfProperties.PRIORITY); if (node != null) { vmBase.setPriority(Integer.parseInt(node.innerText)); } node = selectSingleNode(content, OvfProperties.IS_BOOT_MENU_ENABLED); if (node != null) { vmBase.setBootMenuEnabled(Boolean.parseBoolean(node.innerText)); } node = selectSingleNode(content, OvfProperties.IS_SPICE_FILE_TRANSFER_ENABLED); if (node != null) { vmBase.setSpiceFileTransferEnabled(Boolean.parseBoolean(node.innerText)); } node = selectSingleNode(content, OvfProperties.IS_SPICE_COPY_PASTE_ENABLED); if (node != null) { vmBase.setSpiceCopyPasteEnabled(Boolean.parseBoolean(node.innerText)); } node = selectSingleNode(content, OvfProperties.ALLOW_CONSOLE_RECONNECT); if (node != null) { vmBase.setAllowConsoleReconnect(Boolean.parseBoolean(node.innerText)); } node = selectSingleNode(content, OvfProperties.IS_AUTO_CONVERGE); if (node != null) { if (StringUtils.isNotEmpty(node.innerText)) { vmBase.setAutoConverge(Boolean.parseBoolean(node.innerText)); } } node = selectSingleNode(content, OvfProperties.IS_MIGRATE_COMPRESSED); if (node != null) { if (StringUtils.isNotEmpty(node.innerText)) { vmBase.setMigrateCompressed(Boolean.parseBoolean(node.innerText)); } } node = selectSingleNode(content, OvfProperties.MIGRATION_POLICY_ID); if (node != null) { if (StringUtils.isNotEmpty(node.innerText)) { vmBase.setMigrationPolicyId(Guid.createGuidFromString(node.innerText)); } } node = selectSingleNode(content, OvfProperties.CUSTOM_EMULATED_MACHINE); if (node != null) { if (StringUtils.isNotEmpty(node.innerText)) { vmBase.setCustomEmulatedMachine(node.innerText); } } node = selectSingleNode(content, OvfProperties.CUSTOM_CPU_NAME); if (node != null) { if (StringUtils.isNotEmpty(node.innerText)) { vmBase.setCustomCpuName(node.innerText); } } node = selectSingleNode(content, OvfProperties.PREDEFINED_PROPERTIES); if (node != null) { if (StringUtils.isNotEmpty(node.innerText)) { vmBase.setPredefinedProperties(node.innerText); } } node = selectSingleNode(content, OvfProperties.USER_DEFINED_PROPERTIES); if (node != null) { if (StringUtils.isNotEmpty(node.innerText)) { vmBase.setUserDefinedProperties(node.innerText); } } node = selectSingleNode(content, OvfProperties.MAX_MEMORY_SIZE_MB); if (node != null) { if (StringUtils.isNotEmpty(node.innerText)) { vmBase.setMaxMemorySizeMb(Integer.parseInt(node.innerText)); } } vmBase.setCustomProperties(VmPropertiesUtils.getInstance().customProperties( vmBase.getPredefinedProperties(), vmBase.getUserDefinedProperties())); node = selectSingleNode(content, OvfProperties.VM_LEASE); if (node != null) { if (StringUtils.isNotEmpty(node.innerText)) { vmBase.setLeaseStorageDomainId(new Guid(node.innerText)); } } readGeneralData(content); readVmInit(content); } private void readDedicatedHostsList() { vmBase.setDedicatedVmForVdsList(new LinkedList<>()); // initialize to empty list // search all dedicated hosts with xPath XmlNodeList hostsList = selectNodes(_document, "//*/Content/" + OvfProperties.DEDICATED_VM_FOR_VDS); for (XmlNode hostNode : hostsList) { if (hostNode != null && StringUtils.isNotEmpty(hostNode.innerText)) { vmBase.getDedicatedVmForVdsList().add(Guid.createGuidFromString(hostNode.innerText)); } } } private void readVmInit(XmlNode content) { XmlNode node = selectSingleNode(content, "VmInit"); VmInit vmInit = vmBase.getVmInit(); vmInit.setId(vmBase.getId()); if (node != null) { if (node.attributes.get("ovf:hostname") != null) { vmInit.setHostname(node.attributes.get("ovf:hostname").getValue()); } if (node.attributes.get("ovf:domain") != null) { vmInit.setDomain(node.attributes.get("ovf:domain").getValue()); } if (node.attributes.get("ovf:timeZone") != null) { vmInit.setTimeZone(node.attributes.get("ovf:timeZone").getValue()); } if (node.attributes.get("ovf:authorizedKeys") != null) { vmInit.setAuthorizedKeys(node.attributes.get("ovf:authorizedKeys").getValue()); } if (node.attributes.get("ovf:regenerateKeys") != null) { vmInit.setRegenerateKeys(Boolean.parseBoolean(node.attributes.get("ovf:regenerateKeys").getValue())); } if (node.attributes.get("ovf:dnsServers") != null) { vmInit.setDnsServers(node.attributes.get("ovf:dnsServers").getValue()); } if (node.attributes.get("ovf:dnsSearch") != null) { vmInit.setDnsSearch(node.attributes.get("ovf:dnsSearch").getValue()); } if (node.attributes.get("ovf:networks") != null) { vmInit.setNetworks(VmInitUtils.jsonNetworksToList(node.attributes.get("ovf:networks").getValue())); } if (node.attributes.get("ovf:winKey") != null) { vmInit.setWinKey(node.attributes.get("ovf:winKey").getValue()); } if (node.attributes.get("ovf:rootPassword") != null) { vmInit.setRootPassword(node.attributes.get("ovf:rootPassword").getValue()); } if (node.attributes.get("ovf:customScript") != null) { vmInit.setCustomScript(node.attributes.get("ovf:customScript").getValue()); } } } private XmlNode getNode(XmlNodeList nodeList, String attributeName, String attributeValue) { for (XmlNode section : nodeList) { String value = section.attributes.get(attributeName).getValue(); if (value.equals(attributeValue)) { return section; } } return null; } protected void readSnapshotsSection(@SuppressWarnings("unused") XmlNode section) { // The snapshot section only has meaning for VMs, and is overridden in OvfVmReader. } protected abstract void readGeneralData(XmlNode content); protected void buildNicReference() { XmlNodeList list = selectNodes(_document, "//*/Nic", _xmlNS); for (XmlNode node : list) { VmNetworkInterface iface = new VmNetworkInterface(); iface.setId(new Guid(node.attributes.get("ovf:id").getValue())); interfaces.add(iface); } if (!list.iterator().hasNext()) { String pattern = "//*/Item[" + OvfProperties.VMD_RESOURCE_TYPE + "=" + OvfHardware.Network + "]"; list = selectNodes(_document, pattern, _xmlNS); for (XmlNode node : list) { VmNetworkInterface iface = new VmNetworkInterface(); iface.setId(Guid.newGuid()); updateSingleNic(node, iface); interfaces.add(iface); } } } protected void updateSingleNic(XmlNode node, VmNetworkInterface iface) { String networkName = selectSingleNode(node, OvfProperties.VMD_CONNECTION, _xmlNS).innerText; iface.setNetworkName(StringUtils.defaultIfEmpty(networkName, null)); XmlNode vnicProfileNameNode = selectSingleNode(node, OvfProperties.VMD_VNIC_PROFILE_NAME, _xmlNS); iface.setVnicProfileName(vnicProfileNameNode == null ? null : StringUtils.defaultIfEmpty(vnicProfileNameNode.innerText, null)); XmlNode linkedNode = selectSingleNode(node, OvfProperties.VMD_LINKED, _xmlNS); iface.setLinked(linkedNode == null ? true : Boolean.valueOf(linkedNode.innerText)); iface.setName(selectSingleNode(node, OvfProperties.VMD_NAME, _xmlNS).innerText); String resourceSubType = selectSingleNode(node, "rasd:ResourceSubType", _xmlNS).innerText; if (StringUtils.isNotEmpty(resourceSubType)) { iface.setType(Integer.parseInt(resourceSubType)); } XmlNode speed = selectSingleNode(node, "rasd:speed", _xmlNS); iface.setSpeed((speed != null) ? Integer.parseInt(speed.innerText) : VmInterfaceType.forValue(iface.getType()) .getSpeed()); } private void buildImageReference() { XmlNodeList list = selectNodes(_document, "//*/File", _xmlNS); for (XmlNode node : list) { // If the disk storage type is Cinder then override the disk image with Cinder object, otherwise use the disk image. DiskImage disk = new DiskImage(); // If the OVF is old and does not contain any storage type reference then we assume we can only have disk image. if (node.attributes.get("ovf:disk_storage_type") != null) { String diskStorageType = node.attributes.get("ovf:disk_storage_type").getValue(); if (diskStorageType != null && diskStorageType.equals(DiskStorageType.CINDER.name())) { disk = new CinderDisk(); if (node.attributes.get("ovf:cinder_volume_type") != null) { String cinderVolumeType = node.attributes.get("ovf:cinder_volume_type").getValue(); disk.setCinderVolumeType(cinderVolumeType); } } } disk.setImageId(new Guid(node.attributes.get("ovf:id").getValue())); disk.setId(OvfParser.getImageGroupIdFromImageFile(node.attributes.get("ovf:href").getValue())); // Default values: disk.setActive(true); disk.setImageStatus(ImageStatus.OK); disk.setDescription(node.attributes.get("ovf:description").getValue()); disk.setDiskVmElements(Collections.singletonList(new DiskVmElement(disk.getId(), vmBase.getId()))); _images.add(disk); } } private int getResourceType(XmlNode node, String resource) { if (selectSingleNode(node, resource, _xmlNS) != null && !StringUtils.isEmpty(selectSingleNode(node, resource, _xmlNS).innerText)) { return Integer.parseInt(selectSingleNode(node, resource, _xmlNS).innerText); } return -1; } private void setDeviceByResource(XmlNode node, VmDevice vmDevice) { int resourceType = getResourceType(node, OvfProperties.VMD_RESOURCE_TYPE); int resourceSubType = getResourceType(node, OvfProperties.VMD_SUB_RESOURCE_TYPE); if (resourceSubType == -1) { // we need special handling for Monitor to define it as vnc or spice if (Integer.parseInt(OvfHardware.Monitor) == resourceType) { // get number of monitors from VirtualQuantity in OVF if (selectSingleNode(node, OvfProperties.VMD_VIRTUAL_QUANTITY, _xmlNS) != null && !StringUtils.isEmpty(selectSingleNode(node, OvfProperties.VMD_VIRTUAL_QUANTITY, _xmlNS).innerText)) { int virtualQuantity = Integer.parseInt(selectSingleNode(node, OvfProperties.VMD_VIRTUAL_QUANTITY, _xmlNS).innerText); if (virtualQuantity > 1) { vmDevice.setDevice(VmDeviceType.QXL.getName()); } else { // get first supported display device List<Pair<GraphicsType, DisplayType>> supportedGraphicsAndDisplays = osRepository.getGraphicsAndDisplays(vmBase.getOsId(), new Version(getVersion())); if (!supportedGraphicsAndDisplays.isEmpty()) { DisplayType firstDisplayType = supportedGraphicsAndDisplays.get(0).getSecond(); vmDevice.setDevice(firstDisplayType.getDefaultVmDeviceType().getName()); } else { vmDevice.setDevice(VmDeviceType.QXL.getName()); } } } else { // default to spice if quantity not found vmDevice.setDevice(VmDeviceType.QXL.getName()); } } else { vmDevice.setDevice(VmDeviceType.getoVirtDevice(resourceType).getName()); } } else if (Integer.parseInt(OvfHardware.Network) == resourceType) { // handle interfaces with different sub types : we have 0-5 as the VmInterfaceType enum VmInterfaceType nicType = VmInterfaceType.forValue(resourceSubType); if (nicType != null) { if (nicType == VmInterfaceType.pciPassthrough) { vmDevice.setDevice(VmDeviceType.HOST_DEVICE.getName()); } else { vmDevice.setDevice(VmDeviceType.BRIDGE.getName()); } } else { vmDevice.setDevice(VmDeviceType.getoVirtDevice(resourceType).getName()); } } } private void addDefaultGraphicsDevice() { VmDevice device = VmDeviceCommonUtils.findVmDeviceByGeneralType( vmBase.getManagedDeviceMap(), VmDeviceGeneralType.GRAPHICS); if (device != null) { return; } List<Pair<GraphicsType, DisplayType>> graphicsAndDisplays = osRepository.getGraphicsAndDisplays(vmBase.getOsId(), new Version(getVersion())); GraphicsType graphicsType = vmBase.getDefaultDisplayType() == DisplayType.cirrus ? GraphicsType.VNC : GraphicsType.SPICE; GraphicsType supportedGraphicsType = null; for (Pair<GraphicsType, DisplayType> pair : graphicsAndDisplays) { if (pair.getSecond() == vmBase.getDefaultDisplayType()) { if (pair.getFirst() == graphicsType) { supportedGraphicsType = graphicsType; break; } if (supportedGraphicsType == null) { supportedGraphicsType = pair.getFirst(); } } } if (supportedGraphicsType != null) { device = new GraphicsDevice(supportedGraphicsType.getCorrespondingDeviceType()); device.setId(new VmDeviceId(Guid.newGuid(), vmBase.getId())); addManagedVmDevice(device); } else { log.warn("Cannot find any graphics type for display type {} supported by OS {} in compatibility version {}", vmBase.getDefaultDisplayType().name(), osRepository.getOsName(vmBase.getOsId()), getVersion()); } } private void fixDiskVmElements() { // In the time of disk creation the VM ID is an empty Guid, this is changed to the real ID only after the reading // of the OS properties which comes after the disks creation so the disk VM elements are set to the wrong VM ID // this part sets them to the correct VM ID for (DiskImage disk : _images) { disk.getDiskVmElements().forEach(dve -> dve.setId(new VmDeviceId(disk.getId(), vmBase.getId()))); disk.setDiskVmElements(disk.getDiskVmElements()); } } private static Map<String, Object> getMapNode(XmlNode node) { Map<String, Object> returnValue = new HashMap<>(); NodeList list = node.getChildNodes(); for (int index = 0; index < list.getLength(); ++index) { Node currNode = list.item(index); short nodeType = currNode.getNodeType(); if (nodeType == Node.ELEMENT_NODE) { NodeList childNodes = currNode.getChildNodes(); // If the element node has only one child, then it contains the value if (childNodes.getLength() == 1) { Node valueNode = childNodes.item(0); if (valueNode.getNodeType() == Node.TEXT_NODE) { returnValue.put(currNode.getNodeName(), valueNode.getNodeValue()); } } else if (childNodes.getLength() > 1) { // In this case, we have a nested map, so we parse it returnValue.put(currNode.getNodeName(), getMapNode(new XmlNode(currNode))); } } } return returnValue; } protected XmlNode selectSingleNode(XmlDocument doc, String pattern) { return selectSingleNode(doc, pattern, null); } protected XmlNode selectSingleNode(XmlDocument doc, String pattern, XmlNamespaceManager ns) { this.lastReadEntry = pattern; if (ns == null) { return doc.selectSingleNode(pattern); } return doc.selectSingleNode(pattern, ns); } protected XmlNodeList selectNodes(XmlDocument doc, String pattern) { return selectNodes(doc, pattern, null); } protected XmlNodeList selectNodes(XmlDocument doc, String pattern, XmlNamespaceManager ns) { this.lastReadEntry = pattern; if (ns == null) { return doc.selectNodes(pattern); } return doc.selectNodes(pattern, ns); } protected XmlNode selectSingleNode(XmlNode node, String pattern) { return selectSingleNode(node, pattern, null); } protected XmlNode selectSingleNode(XmlNode node, String pattern, XmlNamespaceManager ns) { this.lastReadEntry = pattern; if (ns == null) { return node.selectSingleNode(pattern); } return node.selectSingleNode(pattern, ns); } protected XmlNodeList selectNodes(XmlNode node, String pattern) { this.lastReadEntry = pattern; return node.selectNodes(pattern); } public String getLastReadEntry() { return lastReadEntry; } @Override public String getStringRepresentation() { return _document.getOuterXml(); } }