Java tutorial
// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package com.cloud.agent.api.storage; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import com.cloud.configuration.Resource.ResourceType; import com.cloud.exception.InternalErrorException; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.apache.log4j.Logger; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import com.cloud.agent.api.to.DatadiskTO; import com.cloud.utils.exception.CloudRuntimeException; public class OVFHelper { private static final Logger s_logger = Logger.getLogger(OVFHelper.class); /** * Get disk virtual size given its values on fields: 'ovf:capacity' and 'ovf:capacityAllocationUnits' * @param capacity capacity * @param allocationUnits capacity allocation units * @return disk virtual size */ public static Long getDiskVirtualSize(Long capacity, String allocationUnits, String ovfFilePath) throws InternalErrorException { if ((capacity != 0) && (allocationUnits != null)) { long units = 1; if (allocationUnits.equalsIgnoreCase("KB") || allocationUnits.equalsIgnoreCase("KiloBytes") || allocationUnits.equalsIgnoreCase("byte * 2^10")) { units = ResourceType.bytesToKiB; } else if (allocationUnits.equalsIgnoreCase("MB") || allocationUnits.equalsIgnoreCase("MegaBytes") || allocationUnits.equalsIgnoreCase("byte * 2^20")) { units = ResourceType.bytesToMiB; } else if (allocationUnits.equalsIgnoreCase("GB") || allocationUnits.equalsIgnoreCase("GigaBytes") || allocationUnits.equalsIgnoreCase("byte * 2^30")) { units = ResourceType.bytesToGiB; } return capacity * units; } else { throw new InternalErrorException( "Failed to read capacity and capacityAllocationUnits from the OVF file: " + ovfFilePath); } } public List<DatadiskTO> getOVFVolumeInfo(final String ovfFilePath) { if (StringUtils.isBlank(ovfFilePath)) { return new ArrayList<DatadiskTO>(); } ArrayList<OVFFile> vf = new ArrayList<OVFFile>(); ArrayList<OVFDisk> vd = new ArrayList<OVFDisk>(); File ovfFile = new File(ovfFilePath); try { final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder() .parse(new File(ovfFilePath)); NodeList disks = doc.getElementsByTagName("Disk"); NodeList files = doc.getElementsByTagName("File"); NodeList items = doc.getElementsByTagName("Item"); boolean toggle = true; for (int j = 0; j < files.getLength(); j++) { Element file = (Element) files.item(j); OVFFile of = new OVFFile(); of._href = file.getAttribute("ovf:href"); if (of._href.endsWith("vmdk") || of._href.endsWith("iso")) { of._id = file.getAttribute("ovf:id"); String size = file.getAttribute("ovf:size"); if (StringUtils.isNotBlank(size)) { of._size = Long.parseLong(size); } else { String dataDiskPath = ovfFile.getParent() + File.separator + of._href; File this_file = new File(dataDiskPath); of._size = this_file.length(); } of.isIso = of._href.endsWith("iso"); if (toggle && !of.isIso) { of._bootable = true; toggle = !toggle; } vf.add(of); } } for (int i = 0; i < disks.getLength(); i++) { Element disk = (Element) disks.item(i); OVFDisk od = new OVFDisk(); String virtualSize = disk.getAttribute("ovf:capacity"); od._capacity = NumberUtils.toLong(virtualSize, 0L); String allocationUnits = disk.getAttribute("ovf:capacityAllocationUnits"); od._diskId = disk.getAttribute("ovf:diskId"); od._fileRef = disk.getAttribute("ovf:fileRef"); od._populatedSize = Long.parseLong(disk.getAttribute("ovf:populatedSize") == null ? "0" : disk.getAttribute("ovf:populatedSize")); if ((od._capacity != 0) && (allocationUnits != null)) { long units = 1; if (allocationUnits.equalsIgnoreCase("KB") || allocationUnits.equalsIgnoreCase("KiloBytes") || allocationUnits.equalsIgnoreCase("byte * 2^10")) { units = ResourceType.bytesToKiB; } else if (allocationUnits.equalsIgnoreCase("MB") || allocationUnits.equalsIgnoreCase("MegaBytes") || allocationUnits.equalsIgnoreCase("byte * 2^20")) { units = ResourceType.bytesToMiB; } else if (allocationUnits.equalsIgnoreCase("GB") || allocationUnits.equalsIgnoreCase("GigaBytes") || allocationUnits.equalsIgnoreCase("byte * 2^30")) { units = ResourceType.bytesToGiB; } od._capacity = od._capacity * units; } od._controller = getControllerType(items, od._diskId); vd.add(od); } } catch (SAXException | IOException | ParserConfigurationException e) { s_logger.error("Unexpected exception caught while parsing ovf file:" + ovfFilePath, e); throw new CloudRuntimeException(e); } List<DatadiskTO> disksTO = new ArrayList<DatadiskTO>(); for (OVFFile of : vf) { if (StringUtils.isBlank(of._id)) { s_logger.error("The ovf file info is incomplete file info"); throw new CloudRuntimeException("The ovf file info has incomplete file info"); } OVFDisk cdisk = getDisk(of._id, vd); if (cdisk == null && !of.isIso) { s_logger.error("The ovf file info has incomplete disk info"); throw new CloudRuntimeException("The ovf file info has incomplete disk info"); } Long capacity = cdisk == null ? of._size : cdisk._capacity; String controller = cdisk == null ? "" : cdisk._controller._name; String controllerSubType = cdisk == null ? "" : cdisk._controller._subType; String dataDiskPath = ovfFile.getParent() + File.separator + of._href; File f = new File(dataDiskPath); if (!f.exists() || f.isDirectory()) { s_logger.error("One of the attached disk or iso does not exists " + dataDiskPath); throw new CloudRuntimeException( "One of the attached disk or iso as stated on OVF does not exists " + dataDiskPath); } disksTO.add(new DatadiskTO(dataDiskPath, capacity, of._size, of._id, of.isIso, of._bootable, controller, controllerSubType)); } //check if first disk is an iso move it to the end DatadiskTO fd = disksTO.get(0); if (fd.isIso()) { disksTO.remove(0); disksTO.add(fd); } return disksTO; } private OVFDiskController getControllerType(final NodeList itemList, final String diskId) { for (int k = 0; k < itemList.getLength(); k++) { Element item = (Element) itemList.item(k); NodeList cn = item.getChildNodes(); for (int l = 0; l < cn.getLength(); l++) { if (cn.item(l) instanceof Element) { Element el = (Element) cn.item(l); if ("rasd:HostResource".equals(el.getNodeName()) && (el.getTextContent().contains("ovf:/file/" + diskId) || el.getTextContent().contains("ovf:/disk/" + diskId))) { Element oe = getParentNode(itemList, item); Element voe = oe; while (oe != null) { voe = oe; oe = getParentNode(itemList, voe); } return getController(voe); } } } } return null; } private Element getParentNode(final NodeList itemList, final Element childItem) { NodeList cn = childItem.getChildNodes(); String parent_id = null; for (int l = 0; l < cn.getLength(); l++) { if (cn.item(l) instanceof Element) { Element el = (Element) cn.item(l); if ("rasd:Parent".equals(el.getNodeName())) { parent_id = el.getTextContent(); } } } if (parent_id != null) { for (int k = 0; k < itemList.getLength(); k++) { Element item = (Element) itemList.item(k); NodeList child = item.getChildNodes(); for (int l = 0; l < child.getLength(); l++) { if (child.item(l) instanceof Element) { Element el = (Element) child.item(l); if ("rasd:InstanceID".equals(el.getNodeName()) && el.getTextContent().trim().equals(parent_id)) { return item; } } } } } return null; } private OVFDiskController getController(Element controllerItem) { OVFDiskController dc = new OVFDiskController(); NodeList child = controllerItem.getChildNodes(); for (int l = 0; l < child.getLength(); l++) { if (child.item(l) instanceof Element) { Element el = (Element) child.item(l); if ("rasd:ElementName".equals(el.getNodeName())) { dc._name = el.getTextContent(); } if ("rasd:ResourceSubType".equals(el.getNodeName())) { dc._subType = el.getTextContent(); } } } return dc; } public void rewriteOVFFile(final String origOvfFilePath, final String newOvfFilePath, final String diskName) { try { final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder() .parse(new File(origOvfFilePath)); NodeList disks = doc.getElementsByTagName("Disk"); NodeList files = doc.getElementsByTagName("File"); NodeList items = doc.getElementsByTagName("Item"); String keepfile = null; List<Element> toremove = new ArrayList<Element>(); for (int j = 0; j < files.getLength(); j++) { Element file = (Element) files.item(j); String href = file.getAttribute("ovf:href"); if (diskName.equals(href)) { keepfile = file.getAttribute("ovf:id"); } else { toremove.add(file); } } String keepdisk = null; for (int i = 0; i < disks.getLength(); i++) { Element disk = (Element) disks.item(i); String fileRef = disk.getAttribute("ovf:fileRef"); if (keepfile == null) { s_logger.info("FATAL: OVA format error"); } else if (keepfile.equals(fileRef)) { keepdisk = disk.getAttribute("ovf:diskId"); } else { toremove.add(disk); } } for (int k = 0; k < items.getLength(); k++) { Element item = (Element) items.item(k); NodeList cn = item.getChildNodes(); for (int l = 0; l < cn.getLength(); l++) { if (cn.item(l) instanceof Element) { Element el = (Element) cn.item(l); if ("rasd:HostResource".equals(el.getNodeName()) && !(el.getTextContent().contains("ovf:/file/" + keepdisk) || el.getTextContent().contains("ovf:/disk/" + keepdisk))) { toremove.add(item); break; } } } } for (Element rme : toremove) { if (rme.getParentNode() != null) { rme.getParentNode().removeChild(rme); } } final StringWriter writer = new StringWriter(); final StreamResult result = new StreamResult(writer); final TransformerFactory tf = TransformerFactory.newInstance(); final Transformer transformer = tf.newTransformer(); final DOMSource domSource = new DOMSource(doc); transformer.transform(domSource, result); PrintWriter outfile = new PrintWriter(newOvfFilePath); outfile.write(writer.toString()); outfile.close(); } catch (SAXException | IOException | ParserConfigurationException | TransformerException e) { s_logger.info("Unexpected exception caught while removing network elements from OVF:" + e.getMessage(), e); throw new CloudRuntimeException(e); } } OVFDisk getDisk(String fileRef, List<OVFDisk> disks) { for (OVFDisk disk : disks) { if (disk._fileRef.equals(fileRef)) { return disk; } } return null; } class OVFFile { // <File ovf:href="i-2-8-VM-disk2.vmdk" ovf:id="file1" ovf:size="69120" /> public String _href; public String _id; public Long _size; public boolean _bootable; public boolean isIso; } class OVFDisk { //<Disk ovf:capacity="50" ovf:capacityAllocationUnits="byte * 2^20" ovf:diskId="vmdisk2" ovf:fileRef="file2" //ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" ovf:populatedSize="43319296" /> public Long _capacity; public String _capacityUnit; public String _diskId; public String _fileRef; public Long _populatedSize; public OVFDiskController _controller; } class OVFDiskController { public String _name; public String _subType; } }