mirror of https://github.com/apache/cloudstack.git
Merge branch '4.16' into main
This commit is contained in:
commit
982eef202f
|
|
@ -19,7 +19,6 @@ package com.cloud.agent.api.storage;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
|
@ -30,9 +29,6 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
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;
|
||||
|
|
@ -55,21 +51,29 @@ 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.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.w3c.dom.traversal.DocumentTraversal;
|
||||
import org.w3c.dom.traversal.NodeFilter;
|
||||
import org.w3c.dom.traversal.NodeIterator;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.cloud.agent.api.to.DatadiskTO;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
public class OVFHelper {
|
||||
private static final Logger s_logger = Logger.getLogger(OVFHelper.class);
|
||||
|
||||
private final OVFParser ovfParser;
|
||||
|
||||
public OVFHelper() {
|
||||
ovfParser = new OVFParser();
|
||||
}
|
||||
|
||||
public OVFParser getOvfParser() {
|
||||
return this.ovfParser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get disk virtual size given its values on fields: 'ovf:capacity' and 'ovf:capacityAllocationUnits'
|
||||
* @param capacity capacity
|
||||
|
|
@ -92,91 +96,27 @@ public class OVFHelper {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text value of a node's child with name or suffix "childNodeName", null if not present
|
||||
* Example:
|
||||
* <Node>
|
||||
* <childNodeName>Text value</childNodeName>
|
||||
* <rasd:childNodeName>Text value</rasd:childNodeName>
|
||||
* </Node>
|
||||
*/
|
||||
private String getChildNodeValue(Node node, String childNodeName) {
|
||||
if (node != null && node.hasChildNodes()) {
|
||||
NodeList childNodes = node.getChildNodes();
|
||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||
Node value = childNodes.item(i);
|
||||
// Also match if the child's name has a suffix:
|
||||
// Example: <rasd:AllocationUnits>
|
||||
if (value != null && (value.getNodeName().equals(childNodeName)) || value.getNodeName().endsWith(":" + childNodeName)) {
|
||||
return value.getTextContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there are elements matching the tag name, otherwise check prepending the prefix
|
||||
*/
|
||||
public NodeList getElementsByTagNameAndPrefix(Document doc, String name, String prefix) {
|
||||
if (doc == null) {
|
||||
return null;
|
||||
}
|
||||
NodeList elementsByTagName = doc.getElementsByTagName(name);
|
||||
if (elementsByTagName.getLength() > 0) {
|
||||
return elementsByTagName;
|
||||
}
|
||||
return doc.getElementsByTagName(String.format("%s:%s", prefix, name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the attribute is present on the element, otherwise check preprending ':'
|
||||
*/
|
||||
private String getNodeAttribute(Element element, String prefix, String attr) {
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
if (element.hasAttribute(prefix + ":" + attr)) {
|
||||
return element.getAttribute(prefix + ":" + attr);
|
||||
}
|
||||
else if (element.hasAttribute(attr)) {
|
||||
return element.getAttribute(attr);
|
||||
}
|
||||
|
||||
NamedNodeMap attributes = element.getAttributes();
|
||||
if (attributes == null || attributes.getLength() == 0) {
|
||||
return null;
|
||||
}
|
||||
for (int i = 0; i < attributes.getLength(); i++) {
|
||||
Node node = attributes.item(i);
|
||||
if (node != null && node.getNodeName().endsWith(":" + attr)) {
|
||||
return node.getTextContent();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create OVFProperty class from the parsed node. Note that some fields may not be present.
|
||||
* The key attribute is required
|
||||
*/
|
||||
protected OVFPropertyTO createOVFPropertyFromNode(Node node, int index, String category) {
|
||||
Element element = (Element) node;
|
||||
String key = getNodeAttribute(element, "ovf","key");
|
||||
String key = ovfParser.getNodeAttribute(element, "key");
|
||||
if (StringUtils.isBlank(key)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String value = getNodeAttribute(element, "ovf","value");
|
||||
String type = getNodeAttribute(element, "ovf","type");
|
||||
String qualifiers = getNodeAttribute(element, "ovf","qualifiers");
|
||||
String userConfigurableStr = getNodeAttribute(element, "ovf","userConfigurable");
|
||||
String value = ovfParser.getNodeAttribute(element, "value");
|
||||
String type = ovfParser.getNodeAttribute(element, "type");
|
||||
String qualifiers = ovfParser.getNodeAttribute(element, "qualifiers");
|
||||
String userConfigurableStr = ovfParser.getNodeAttribute(element, "userConfigurable");
|
||||
boolean userConfigurable = StringUtils.isNotBlank(userConfigurableStr) &&
|
||||
userConfigurableStr.equalsIgnoreCase("true");
|
||||
String passStr = getNodeAttribute(element, "ovf","password");
|
||||
String passStr = ovfParser.getNodeAttribute(element, "password");
|
||||
boolean password = StringUtils.isNotBlank(passStr) && passStr.equalsIgnoreCase("true");
|
||||
String label = getChildNodeValue(node, "Label");
|
||||
String description = getChildNodeValue(node, "Description");
|
||||
String label = ovfParser.getChildNodeValue(node, "Label");
|
||||
String description = ovfParser.getChildNodeValue(node, "Description");
|
||||
s_logger.debug("Creating OVF property index " + index + (category == null ? "" : " for category " + category)
|
||||
+ " with key = " + key);
|
||||
return new OVFPropertyTO(key, type, value, qualifiers, userConfigurable,
|
||||
|
|
@ -193,7 +133,7 @@ public class OVFHelper {
|
|||
return props;
|
||||
}
|
||||
int propertyIndex = 0;
|
||||
NodeList productSections = getElementsByTagNameAndPrefix(doc, "ProductSection", "ovf");
|
||||
NodeList productSections = ovfParser.getElementsFromOVFDocument(doc, "ProductSection");
|
||||
if (productSections != null) {
|
||||
String lastCategoryFound = null;
|
||||
for (int i = 0; i < productSections.getLength(); i++) {
|
||||
|
|
@ -208,11 +148,11 @@ public class OVFHelper {
|
|||
continue;
|
||||
}
|
||||
if (child.getNodeName().equalsIgnoreCase("Category") ||
|
||||
child.getNodeName().equalsIgnoreCase("ovf:Category")) {
|
||||
child.getNodeName().endsWith(":Category")) {
|
||||
lastCategoryFound = child.getTextContent();
|
||||
s_logger.info("Category found " + lastCategoryFound);
|
||||
} else if (child.getNodeName().equalsIgnoreCase("Property") ||
|
||||
child.getNodeName().equalsIgnoreCase("ovf:Property")) {
|
||||
child.getNodeName().endsWith(":Property")) {
|
||||
OVFPropertyTO prop = createOVFPropertyFromNode(child, propertyIndex, lastCategoryFound);
|
||||
if (prop != null && prop.isUserConfigurable()) {
|
||||
props.add(prop);
|
||||
|
|
@ -228,39 +168,33 @@ public class OVFHelper {
|
|||
/**
|
||||
* Get properties from OVF XML string
|
||||
*/
|
||||
protected List<OVFPropertyTO> getOVFPropertiesFromXmlString(final String ovfString) throws ParserConfigurationException, IOException, SAXException {
|
||||
InputSource is = new InputSource(new StringReader(ovfString));
|
||||
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
|
||||
protected List<OVFPropertyTO> getOVFPropertiesFromXmlString(final String ovfString) throws IOException, SAXException {
|
||||
final Document doc = ovfParser.parseOVF(ovfString);
|
||||
return getConfigurableOVFPropertiesFromDocument(doc);
|
||||
}
|
||||
|
||||
protected Pair<String, String> getOperatingSystemInfoFromXmlString(final String ovfString) throws ParserConfigurationException, IOException, SAXException {
|
||||
InputSource is = new InputSource(new StringReader(ovfString));
|
||||
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
|
||||
protected Pair<String, String> getOperatingSystemInfoFromXmlString(final String ovfString) throws IOException, SAXException {
|
||||
final Document doc = ovfParser.parseOVF(ovfString);
|
||||
return getOperatingSystemInfoFromDocument(doc);
|
||||
}
|
||||
|
||||
protected List<OVFConfigurationTO> getOVFDeploymentOptionsFromXmlString(final String ovfString) throws ParserConfigurationException, IOException, SAXException {
|
||||
InputSource is = new InputSource(new StringReader(ovfString));
|
||||
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
|
||||
protected List<OVFConfigurationTO> getOVFDeploymentOptionsFromXmlString(final String ovfString) throws IOException, SAXException {
|
||||
final Document doc = ovfParser.parseOVF(ovfString);
|
||||
return getDeploymentOptionsFromDocumentTree(doc);
|
||||
}
|
||||
|
||||
protected List<OVFVirtualHardwareItemTO> getOVFVirtualHardwareSectionFromXmlString(final String ovfString) throws ParserConfigurationException, IOException, SAXException {
|
||||
InputSource is = new InputSource(new StringReader(ovfString));
|
||||
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
|
||||
protected List<OVFVirtualHardwareItemTO> getOVFVirtualHardwareSectionFromXmlString(final String ovfString) throws IOException, SAXException {
|
||||
final Document doc = ovfParser.parseOVF(ovfString);
|
||||
return getVirtualHardwareItemsFromDocumentTree(doc);
|
||||
}
|
||||
|
||||
protected OVFVirtualHardwareSectionTO getVirtualHardwareSectionFromXmlString(final String ovfString) throws ParserConfigurationException, IOException, SAXException {
|
||||
InputSource is = new InputSource(new StringReader(ovfString));
|
||||
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
|
||||
protected OVFVirtualHardwareSectionTO getVirtualHardwareSectionFromXmlString(final String ovfString) throws IOException, SAXException {
|
||||
final Document doc = ovfParser.parseOVF(ovfString);
|
||||
return getVirtualHardwareSectionFromDocument(doc);
|
||||
}
|
||||
|
||||
protected List<OVFEulaSectionTO> getOVFEulaSectionFromXmlString(final String ovfString) throws ParserConfigurationException, IOException, SAXException {
|
||||
InputSource is = new InputSource(new StringReader(ovfString));
|
||||
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
|
||||
protected List<OVFEulaSectionTO> getOVFEulaSectionFromXmlString(final String ovfString) throws IOException, SAXException {
|
||||
final Document doc = ovfParser.parseOVF(ovfString);
|
||||
return getEulaSectionsFromDocument(doc);
|
||||
}
|
||||
|
||||
|
|
@ -268,7 +202,7 @@ public class OVFHelper {
|
|||
if (StringUtils.isBlank(ovfFilePath)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
Document doc = getDocumentFromFile(ovfFilePath);
|
||||
Document doc = ovfParser.parseOVFFile(ovfFilePath);
|
||||
|
||||
return getOVFVolumeInfoFromFile(ovfFilePath, doc, configurationId);
|
||||
}
|
||||
|
|
@ -287,8 +221,7 @@ public class OVFHelper {
|
|||
.filter(x -> x.getResourceType() == OVFVirtualHardwareItemTO.HardwareResourceType.DiskDrive &&
|
||||
hardwareItemContainsConfiguration(x, configurationId))
|
||||
.collect(Collectors.toList());
|
||||
List<DatadiskTO> diskTOs = matchHardwareItemsToDiskAndFilesInformation(diskHardwareItems, files, disks, ovfFile.getParent());
|
||||
return diskTOs;
|
||||
return matchHardwareItemsToDiskAndFilesInformation(diskHardwareItems, files, disks, ovfFile.getParent());
|
||||
}
|
||||
|
||||
private String extractDiskIdFromDiskHostResource(String hostResource) {
|
||||
|
|
@ -367,31 +300,23 @@ public class OVFHelper {
|
|||
}
|
||||
|
||||
protected List<OVFDisk> extractDisksFromOvfDocumentTree(Document doc) {
|
||||
NodeList disks = doc.getElementsByTagName("Disk");
|
||||
NodeList ovfDisks = doc.getElementsByTagName("ovf:Disk");
|
||||
NodeList items = doc.getElementsByTagName("Item");
|
||||
NodeList disks = ovfParser.getElementsFromOVFDocument(doc, "Disk");
|
||||
NodeList items = ovfParser.getElementsFromOVFDocument(doc, "Item");
|
||||
|
||||
int totalDisksLength = disks.getLength() + ovfDisks.getLength();
|
||||
ArrayList<OVFDisk> vd = new ArrayList<>();
|
||||
for (int i = 0; i < totalDisksLength; i++) {
|
||||
Element disk;
|
||||
if (i >= disks.getLength()) {
|
||||
int pos = i - disks.getLength();
|
||||
disk = (Element) ovfDisks.item(pos);
|
||||
} else {
|
||||
disk = (Element) disks.item(i);
|
||||
}
|
||||
for (int i = 0; i < disks.getLength(); i++) {
|
||||
Element disk = (Element) disks.item(i);
|
||||
|
||||
if (disk == null) {
|
||||
continue;
|
||||
}
|
||||
OVFDisk od = new OVFDisk();
|
||||
String virtualSize = getNodeAttribute(disk, "ovf", "capacity");
|
||||
String virtualSize = ovfParser.getNodeAttribute(disk, "capacity");
|
||||
od._capacity = NumberUtils.toLong(virtualSize, 0L);
|
||||
String allocationUnits = getNodeAttribute(disk,"ovf","capacityAllocationUnits");
|
||||
od._diskId = getNodeAttribute(disk,"ovf","diskId");
|
||||
od._fileRef = getNodeAttribute(disk,"ovf","fileRef");
|
||||
od._populatedSize = NumberUtils.toLong(getNodeAttribute(disk,"ovf","populatedSize"));
|
||||
String allocationUnits = ovfParser.getNodeAttribute(disk, "capacityAllocationUnits");
|
||||
od._diskId = ovfParser.getNodeAttribute(disk, "diskId");
|
||||
od._fileRef = ovfParser.getNodeAttribute(disk, "fileRef");
|
||||
od._populatedSize = NumberUtils.toLong(ovfParser.getNodeAttribute(disk, "populatedSize"));
|
||||
|
||||
if ((od._capacity != 0) && (allocationUnits != null)) {
|
||||
long units = 1;
|
||||
|
|
@ -414,16 +339,16 @@ public class OVFHelper {
|
|||
}
|
||||
|
||||
protected List<OVFFile> extractFilesFromOvfDocumentTree(File ovfFile, Document doc) {
|
||||
NodeList files = getElementsByTagNameAndPrefix(doc, "File", "ovf");
|
||||
NodeList files = ovfParser.getElementsFromOVFDocument(doc, "File");
|
||||
ArrayList<OVFFile> vf = new ArrayList<>();
|
||||
boolean toggle = true;
|
||||
for (int j = 0; j < files.getLength(); j++) {
|
||||
Element file = (Element)files.item(j);
|
||||
OVFFile of = new OVFFile();
|
||||
of._href = getNodeAttribute(file,"ovf","href");
|
||||
of._href = ovfParser.getNodeAttribute(file, "href");
|
||||
if (of._href.endsWith("vmdk") || of._href.endsWith("iso")) {
|
||||
of._id = getNodeAttribute(file,"ovf","id");
|
||||
String size = getNodeAttribute(file,"ovf", "size");
|
||||
of._id = ovfParser.getNodeAttribute(file, "id");
|
||||
String size = ovfParser.getNodeAttribute(file, "size");
|
||||
if (StringUtils.isNotBlank(size)) {
|
||||
of._size = Long.parseLong(size);
|
||||
} else {
|
||||
|
|
@ -445,20 +370,6 @@ public class OVFHelper {
|
|||
return vf;
|
||||
}
|
||||
|
||||
public Document getDocumentFromFile(String ovfFilePath) {
|
||||
if (StringUtils.isBlank(ovfFilePath)) {
|
||||
return null;
|
||||
}
|
||||
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newDefaultInstance();
|
||||
try {
|
||||
DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
|
||||
return builder.parse(new File(ovfFilePath));
|
||||
} catch (SAXException | IOException | ParserConfigurationException e) {
|
||||
s_logger.error("Unexpected exception caught while parsing ovf file:" + ovfFilePath, e);
|
||||
throw new CloudRuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private OVFDiskController getControllerType(final NodeList itemList, final String diskId) {
|
||||
for (int k = 0; k < itemList.getLength(); k++) {
|
||||
Element item = (Element)itemList.item(k);
|
||||
|
|
@ -528,18 +439,18 @@ public class OVFHelper {
|
|||
}
|
||||
|
||||
public void rewriteOVFFileForSingleDisk(final String origOvfFilePath, final String newOvfFilePath, final String diskName) {
|
||||
final Document doc = getDocumentFromFile(origOvfFilePath);
|
||||
final Document doc = ovfParser.parseOVFFile(origOvfFilePath);
|
||||
|
||||
NodeList disks = getElementsByTagNameAndPrefix(doc, "Disk", "ovf");
|
||||
NodeList files = getElementsByTagNameAndPrefix(doc, "File", "ovf");
|
||||
NodeList items = getElementsByTagNameAndPrefix(doc, "Item", "ovf");
|
||||
NodeList disks = ovfParser.getElementsFromOVFDocument(doc, "Disk");
|
||||
NodeList files = ovfParser.getElementsFromOVFDocument(doc, "File");
|
||||
NodeList items = ovfParser.getElementsFromOVFDocument(doc, "Item");
|
||||
String keepfile = null;
|
||||
List<Element> toremove = new ArrayList<>();
|
||||
for (int j = 0; j < files.getLength(); j++) {
|
||||
Element file = (Element)files.item(j);
|
||||
String href = getNodeAttribute(file,"ovf", "href");
|
||||
String href = ovfParser.getNodeAttribute(file, "href");
|
||||
if (diskName.equals(href)) {
|
||||
keepfile = getNodeAttribute(file,"ovf","id");
|
||||
keepfile = ovfParser.getNodeAttribute(file, "id");
|
||||
} else {
|
||||
toremove.add(file);
|
||||
}
|
||||
|
|
@ -547,11 +458,11 @@ public class OVFHelper {
|
|||
String keepdisk = null;
|
||||
for (int i = 0; i < disks.getLength(); i++) {
|
||||
Element disk = (Element)disks.item(i);
|
||||
String fileRef = getNodeAttribute(disk,"ovf","fileRef");
|
||||
String fileRef = ovfParser.getNodeAttribute(disk, "fileRef");
|
||||
if (keepfile == null) {
|
||||
s_logger.info("FATAL: OVA format error");
|
||||
} else if (keepfile.equals(fileRef)) {
|
||||
keepdisk = getNodeAttribute(disk,"ovf","diskId");
|
||||
keepdisk = ovfParser.getNodeAttribute(disk, "diskId");
|
||||
} else {
|
||||
toremove.add(disk);
|
||||
}
|
||||
|
|
@ -660,13 +571,13 @@ public class OVFHelper {
|
|||
* @param parentNode the xml container node for nic data
|
||||
*/
|
||||
private void fillNicPrerequisites(OVFNetworkTO nic, Node parentNode) {
|
||||
String addressOnParentStr = getChildNodeValue(parentNode, "AddressOnParent");
|
||||
String automaticAllocationStr = getChildNodeValue(parentNode, "AutomaticAllocation");
|
||||
String description = getChildNodeValue(parentNode, "Description");
|
||||
String elementName = getChildNodeValue(parentNode, "ElementName");
|
||||
String instanceIdStr = getChildNodeValue(parentNode, "InstanceID");
|
||||
String resourceSubType = getChildNodeValue(parentNode, "ResourceSubType");
|
||||
String resourceType = getChildNodeValue(parentNode, "ResourceType");
|
||||
String addressOnParentStr = ovfParser.getChildNodeValue(parentNode, "AddressOnParent");
|
||||
String automaticAllocationStr = ovfParser.getChildNodeValue(parentNode, "AutomaticAllocation");
|
||||
String description = ovfParser.getChildNodeValue(parentNode, "Description");
|
||||
String elementName = ovfParser.getChildNodeValue(parentNode, "ElementName");
|
||||
String instanceIdStr = ovfParser.getChildNodeValue(parentNode, "InstanceID");
|
||||
String resourceSubType = ovfParser.getChildNodeValue(parentNode, "ResourceSubType");
|
||||
String resourceType = ovfParser.getChildNodeValue(parentNode, "ResourceType");
|
||||
|
||||
try {
|
||||
int addressOnParent = Integer.parseInt(addressOnParentStr);
|
||||
|
|
@ -693,7 +604,7 @@ public class OVFHelper {
|
|||
|
||||
private void checkForOnlyOneSystemNode(Document doc) throws InternalErrorException {
|
||||
// get hardware VirtualSystem, for now we support only one of those
|
||||
NodeList systemElements = getElementsByTagNameAndPrefix(doc, "VirtualSystem", "ovf");
|
||||
NodeList systemElements = ovfParser.getElementsFromOVFDocument(doc, "VirtualSystem");
|
||||
if (systemElements.getLength() != 1) {
|
||||
String msg = "found " + systemElements.getLength() + " system definitions in OVA, can only handle exactly one.";
|
||||
s_logger.warn(msg);
|
||||
|
|
@ -702,14 +613,14 @@ public class OVFHelper {
|
|||
}
|
||||
|
||||
private Map<String, OVFNetworkTO> getNetworksFromDocumentTree(Document doc) {
|
||||
NodeList networkElements = getElementsByTagNameAndPrefix(doc,"Network", "ovf");
|
||||
NodeList networkElements = ovfParser.getElementsFromOVFDocument(doc,"Network");
|
||||
Map<String, OVFNetworkTO> nets = new HashMap<>();
|
||||
for (int i = 0; i < networkElements.getLength(); i++) {
|
||||
|
||||
Element networkElement = (Element)networkElements.item(i);
|
||||
String networkName = getNodeAttribute(networkElement,"ovf","name");
|
||||
String networkName = ovfParser.getNodeAttribute(networkElement, "name");
|
||||
|
||||
String description = getChildNodeValue(networkElement, "Description");
|
||||
String description = ovfParser.getChildNodeValue(networkElement, "Description");
|
||||
|
||||
OVFNetworkTO network = new OVFNetworkTO();
|
||||
network.setName(networkName);
|
||||
|
|
@ -762,10 +673,10 @@ public class OVFHelper {
|
|||
private String getMinimumHardwareVersionFromDocumentTree(Document doc) {
|
||||
String version = null;
|
||||
if (doc != null) {
|
||||
NodeList systemNodeList = getElementsByTagNameAndPrefix(doc, "System", "ovf");
|
||||
NodeList systemNodeList = ovfParser.getElementsFromOVFDocument(doc, "System");
|
||||
if (systemNodeList.getLength() != 0) {
|
||||
Node systemItem = systemNodeList.item(0);
|
||||
String hardwareVersions = getChildNodeValue(systemItem, "VirtualSystemType");
|
||||
String hardwareVersions = ovfParser.getChildNodeValue(systemItem, "VirtualSystemType");
|
||||
if (StringUtils.isNotBlank(hardwareVersions)) {
|
||||
String[] versions = hardwareVersions.split(",");
|
||||
// Order the hardware versions and retrieve the minimum version
|
||||
|
|
@ -782,7 +693,7 @@ public class OVFHelper {
|
|||
if (doc == null) {
|
||||
return options;
|
||||
}
|
||||
NodeList deploymentOptionSection = getElementsByTagNameAndPrefix(doc,"DeploymentOptionSection", "ovf");
|
||||
NodeList deploymentOptionSection = ovfParser.getElementsFromOVFDocument(doc,"DeploymentOptionSection");
|
||||
if (deploymentOptionSection.getLength() == 0) {
|
||||
return options;
|
||||
}
|
||||
|
|
@ -793,9 +704,9 @@ public class OVFHelper {
|
|||
Node node = childNodes.item(i);
|
||||
if (node != null && (node.getNodeName().equals("Configuration") || node.getNodeName().equals("ovf:Configuration"))) {
|
||||
Element configuration = (Element) node;
|
||||
String configurationId = getNodeAttribute(configuration,"ovf","id");
|
||||
String description = getChildNodeValue(configuration, "Description");
|
||||
String label = getChildNodeValue(configuration, "Label");
|
||||
String configurationId = ovfParser.getNodeAttribute(configuration, "id");
|
||||
String description = ovfParser.getChildNodeValue(configuration, "Description");
|
||||
String label = ovfParser.getChildNodeValue(configuration, "Label");
|
||||
OVFConfigurationTO option = new OVFConfigurationTO(configurationId, label, description, index);
|
||||
options.add(option);
|
||||
index++;
|
||||
|
|
@ -809,7 +720,7 @@ public class OVFHelper {
|
|||
if (doc == null) {
|
||||
return items;
|
||||
}
|
||||
NodeList hardwareSection = getElementsByTagNameAndPrefix(doc, "VirtualHardwareSection","ovf");
|
||||
NodeList hardwareSection = ovfParser.getElementsFromOVFDocument(doc, "VirtualHardwareSection");
|
||||
if (hardwareSection.getLength() == 0) {
|
||||
return items;
|
||||
}
|
||||
|
|
@ -819,18 +730,18 @@ public class OVFHelper {
|
|||
Node node = childNodes.item(i);
|
||||
if (node != null && (node.getNodeName().equals("Item") || node.getNodeName().equals("ovf:Item"))) {
|
||||
Element configuration = (Element) node;
|
||||
String configurationIds = getNodeAttribute(configuration, "ovf", "configuration");
|
||||
String allocationUnits = getChildNodeValue(configuration, "AllocationUnits");
|
||||
String description = getChildNodeValue(configuration, "Description");
|
||||
String elementName = getChildNodeValue(configuration, "ElementName");
|
||||
String instanceID = getChildNodeValue(configuration, "InstanceID");
|
||||
String limit = getChildNodeValue(configuration, "Limit");
|
||||
String reservation = getChildNodeValue(configuration, "Reservation");
|
||||
String resourceType = getChildNodeValue(configuration, "ResourceType");
|
||||
String virtualQuantity = getChildNodeValue(configuration, "VirtualQuantity");
|
||||
String hostResource = getChildNodeValue(configuration, "HostResource");
|
||||
String addressOnParent = getChildNodeValue(configuration, "AddressOnParent");
|
||||
String parent = getChildNodeValue(configuration, "Parent");
|
||||
String configurationIds = ovfParser.getNodeAttribute(configuration, "configuration");
|
||||
String allocationUnits = ovfParser.getChildNodeValue(configuration, "AllocationUnits");
|
||||
String description = ovfParser.getChildNodeValue(configuration, "Description");
|
||||
String elementName = ovfParser.getChildNodeValue(configuration, "ElementName");
|
||||
String instanceID = ovfParser.getChildNodeValue(configuration, "InstanceID");
|
||||
String limit = ovfParser.getChildNodeValue(configuration, "Limit");
|
||||
String reservation = ovfParser.getChildNodeValue(configuration, "Reservation");
|
||||
String resourceType = ovfParser.getChildNodeValue(configuration, "ResourceType");
|
||||
String virtualQuantity = ovfParser.getChildNodeValue(configuration, "VirtualQuantity");
|
||||
String hostResource = ovfParser.getChildNodeValue(configuration, "HostResource");
|
||||
String addressOnParent = ovfParser.getChildNodeValue(configuration, "AddressOnParent");
|
||||
String parent = ovfParser.getChildNodeValue(configuration, "Parent");
|
||||
OVFVirtualHardwareItemTO item = new OVFVirtualHardwareItemTO();
|
||||
item.setConfigurationIds(configurationIds);
|
||||
item.setAllocationUnits(allocationUnits);
|
||||
|
|
@ -885,7 +796,7 @@ public class OVFHelper {
|
|||
if (doc == null) {
|
||||
return eulas;
|
||||
}
|
||||
NodeList eulaSections = getElementsByTagNameAndPrefix(doc, "EulaSection", "ovf");
|
||||
NodeList eulaSections = ovfParser.getElementsFromOVFDocument(doc, "EulaSection");
|
||||
int eulaIndex = 0;
|
||||
if (eulaSections.getLength() > 0) {
|
||||
for (int index = 0; index < eulaSections.getLength(); index++) {
|
||||
|
|
@ -921,14 +832,14 @@ public class OVFHelper {
|
|||
if (doc == null) {
|
||||
return null;
|
||||
}
|
||||
NodeList guesOsList = getElementsByTagNameAndPrefix(doc, "OperatingSystemSection", "ovf");
|
||||
NodeList guesOsList = ovfParser.getElementsFromOVFDocument(doc, "OperatingSystemSection");
|
||||
if (guesOsList.getLength() == 0) {
|
||||
return null;
|
||||
}
|
||||
Node guestOsNode = guesOsList.item(0);
|
||||
Element guestOsElement = (Element) guestOsNode;
|
||||
String osType = getNodeAttribute(guestOsElement, "vmw", "osType");
|
||||
String description = getChildNodeValue(guestOsNode, "Description");
|
||||
String osType = ovfParser.getNodeAttribute(guestOsElement, "osType");
|
||||
String description = ovfParser.getChildNodeValue(guestOsNode, "Description");
|
||||
return new Pair<>(osType, description);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,112 @@
|
|||
// 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 org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.Map;
|
||||
|
||||
public class OVFParser {
|
||||
private static final Logger s_logger = Logger.getLogger(OVFParser.class);
|
||||
|
||||
private static final String DEFAULT_OVF_SCHEMA = "http://schemas.dmtf.org/ovf/envelope/1";
|
||||
private static final String VMW_SCHEMA = "http://www.vmware.com/schema/ovf";
|
||||
|
||||
private static final Map<String, String> ATTRIBUTE_SCHEMA_MAP = Map.of(
|
||||
"osType", VMW_SCHEMA
|
||||
);
|
||||
|
||||
private DocumentBuilder documentBuilder;
|
||||
|
||||
public OVFParser() {
|
||||
try {
|
||||
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
documentBuilderFactory.setNamespaceAware(true);
|
||||
documentBuilder = documentBuilderFactory.newDocumentBuilder();
|
||||
} catch (ParserConfigurationException e) {
|
||||
s_logger.error("Cannot start the OVF parser: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public Document parseOVF(String ovfString) throws IOException, SAXException {
|
||||
InputSource is = new InputSource(new StringReader(ovfString));
|
||||
return documentBuilder.parse(is);
|
||||
}
|
||||
|
||||
public Document parseOVFFile(String ovfFilePath) {
|
||||
if (StringUtils.isBlank(ovfFilePath)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return documentBuilder.parse(new File(ovfFilePath));
|
||||
} catch (SAXException | IOException e) {
|
||||
s_logger.error("Error parsing " + ovfFilePath + " " + e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve elements with tag name from the document, according to the OVF schema definition
|
||||
*/
|
||||
public NodeList getElementsFromOVFDocument(Document doc, String tagName) {
|
||||
return doc != null ? doc.getElementsByTagNameNS(DEFAULT_OVF_SCHEMA, tagName) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an attribute value from an OVF element
|
||||
*/
|
||||
public String getNodeAttribute(Element element, String attr) {
|
||||
return element != null ? element.getAttributeNS(ATTRIBUTE_SCHEMA_MAP.getOrDefault(attr, DEFAULT_OVF_SCHEMA), attr) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text value of a node's child with name or suffix "childNodeName", null if not present
|
||||
* Example:
|
||||
* <Node>
|
||||
* <childNodeName>Text value</childNodeName>
|
||||
* <rasd:childNodeName>Text value</rasd:childNodeName>
|
||||
* </Node>
|
||||
*/
|
||||
public String getChildNodeValue(Node node, String childNodeName) {
|
||||
if (node == null || !node.hasChildNodes()) {
|
||||
return null;
|
||||
}
|
||||
NodeList childNodes = node.getChildNodes();
|
||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||
Node value = childNodes.item(i);
|
||||
// Also match if the child's name has a suffix:
|
||||
// Example: <rasd:AllocationUnits>
|
||||
if (value != null && (value.getNodeName().equals(childNodeName)) || value.getNodeName().endsWith(":" + childNodeName)) {
|
||||
return value.getTextContent();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -27,14 +27,13 @@ import org.junit.Test;
|
|||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class OVFHelperTest {
|
||||
|
||||
private String ovfFileProductSection =
|
||||
"<ProductSection>" +
|
||||
"<ProductSection xmlns=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:cim=\"http://schemas.dmtf.org/wbem/wscim/1/common\" xmlns:ovf=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:rasd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData\" xmlns:vmw=\"http://www.vmware.com/schema/ovf\" xmlns:vssd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" +
|
||||
"<Info>VM Arguments</Info>" +
|
||||
"<Property ovf:key=\"va-ssh-public-key\" ovf:type=\"string\" ovf:userConfigurable=\"true\" ovf:value=\"\">" +
|
||||
"<Label>Set the SSH public key allowed to access the appliance</Label>" +
|
||||
|
|
@ -47,7 +46,7 @@ public class OVFHelperTest {
|
|||
"</ProductSection>";
|
||||
|
||||
private String ovfFileDeploymentOptionsSection =
|
||||
"<DeploymentOptionSection>\n" +
|
||||
"<DeploymentOptionSection xmlns=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:cim=\"http://schemas.dmtf.org/wbem/wscim/1/common\" xmlns:ovf=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:rasd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData\" xmlns:vmw=\"http://www.vmware.com/schema/ovf\" xmlns:vssd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
|
||||
" <Info>Deployment Configuration information</Info>\n" +
|
||||
" <Configuration ovf:id=\"ASAv5\">\n" +
|
||||
" <Label>100 Mbps (ASAv5)</Label>\n" +
|
||||
|
|
@ -61,10 +60,10 @@ public class OVFHelperTest {
|
|||
" <Label>2 Gbps (ASAv30)</Label>\n" +
|
||||
" <Description>Use this option to deploy an ASAv with a maximum throughput of 2 Gbps (uses 4 vCPUs and 8 GB of memory).</Description>\n" +
|
||||
" </Configuration>\n" +
|
||||
" </DeploymentOptionSection>";
|
||||
" </DeploymentOptionSection>";
|
||||
|
||||
private String ovfFileVirtualHardwareSection =
|
||||
"<VirtualSystem>\n" +
|
||||
"<VirtualSystem xmlns=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:cim=\"http://schemas.dmtf.org/wbem/wscim/1/common\" xmlns:ovf=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:rasd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData\" xmlns:vmw=\"http://www.vmware.com/schema/ovf\" xmlns:vssd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
|
||||
"<OperatingSystemSection ovf:id=\"100\" vmw:osType=\"other26xLinux64Guest\">\n" +
|
||||
" <Info>The kind of installed guest operating system</Info>\n" +
|
||||
" <Description>Other 2.6x Linux (64-bit)</Description>\n" +
|
||||
|
|
@ -270,7 +269,7 @@ public class OVFHelperTest {
|
|||
"</VirtualSystem>";
|
||||
|
||||
private String eulaSections =
|
||||
"<VirtualSystem>\n" +
|
||||
"<VirtualSystem xmlns=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:cim=\"http://schemas.dmtf.org/wbem/wscim/1/common\" xmlns:ovf=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:rasd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData\" xmlns:vmw=\"http://www.vmware.com/schema/ovf\" xmlns:vssd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
|
||||
"<EulaSection>\n" +
|
||||
" <Info>end-user license agreement</Info>\n" +
|
||||
" <License>END USER LICENSE AGREEMENT\n" +
|
||||
|
|
@ -395,7 +394,7 @@ public class OVFHelperTest {
|
|||
"</VirtualSystem>";
|
||||
|
||||
private String productSectionWithCategories =
|
||||
"<VirtualSystem ovf:id=\"VMware-vCenter-Server-Appliance\">\n" +
|
||||
"<VirtualSystem ovf:id=\"VMware-vCenter-Server-Appliance\" xmlns=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:cim=\"http://schemas.dmtf.org/wbem/wscim/1/common\" xmlns:ovf=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:rasd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData\" xmlns:vmw=\"http://www.vmware.com/schema/ovf\" xmlns:vssd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
|
||||
"<ProductSection ovf:required=\"false\">\n" +
|
||||
" <Info>Appliance ISV branding information</Info>\n" +
|
||||
" <Product>VMware vCenter Server Appliance</Product>\n" +
|
||||
|
|
@ -704,49 +703,49 @@ public class OVFHelperTest {
|
|||
private OVFHelper ovfHelper = new OVFHelper();
|
||||
|
||||
@Test
|
||||
public void testGetOVFPropertiesValidOVF() throws IOException, SAXException, ParserConfigurationException {
|
||||
public void testGetOVFPropertiesValidOVF() throws IOException, SAXException {
|
||||
List<OVFPropertyTO> props = ovfHelper.getOVFPropertiesFromXmlString(ovfFileProductSection);
|
||||
Assert.assertEquals(2, props.size());
|
||||
}
|
||||
|
||||
@Test(expected = SAXParseException.class)
|
||||
public void testGetOVFPropertiesInvalidOVF() throws IOException, SAXException, ParserConfigurationException {
|
||||
public void testGetOVFPropertiesInvalidOVF() throws IOException, SAXException {
|
||||
ovfHelper.getOVFPropertiesFromXmlString(ovfFileProductSection + "xxxxxxxxxxxxxxxxx");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetOVFDeploymentOptionsValidOVF() throws IOException, SAXException, ParserConfigurationException {
|
||||
public void testGetOVFDeploymentOptionsValidOVF() throws IOException, SAXException {
|
||||
List<OVFConfigurationTO> options = ovfHelper.getOVFDeploymentOptionsFromXmlString(ovfFileDeploymentOptionsSection);
|
||||
Assert.assertEquals(3, options.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetOVFVirtualHardwareSectionValidOVF() throws IOException, SAXException, ParserConfigurationException {
|
||||
public void testGetOVFVirtualHardwareSectionValidOVF() throws IOException, SAXException {
|
||||
List<OVFVirtualHardwareItemTO> items = ovfHelper.getOVFVirtualHardwareSectionFromXmlString(ovfFileVirtualHardwareSection);
|
||||
Assert.assertEquals(20, items.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetOVFEulaSectionValidOVF() throws IOException, SAXException, ParserConfigurationException {
|
||||
public void testGetOVFEulaSectionValidOVF() throws IOException, SAXException {
|
||||
List<OVFEulaSectionTO> eulas = ovfHelper.getOVFEulaSectionFromXmlString(eulaSections);
|
||||
Assert.assertEquals(2, eulas.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetOVFPropertiesWithCategories() throws IOException, SAXException, ParserConfigurationException {
|
||||
public void testGetOVFPropertiesWithCategories() throws IOException, SAXException {
|
||||
List<OVFPropertyTO> props = ovfHelper.getOVFPropertiesFromXmlString(productSectionWithCategories);
|
||||
Assert.assertEquals(18, props.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetOperatingSystemInfo() throws IOException, SAXException, ParserConfigurationException {
|
||||
public void testGetOperatingSystemInfo() throws IOException, SAXException {
|
||||
Pair<String, String> guestOsPair = ovfHelper.getOperatingSystemInfoFromXmlString(ovfFileVirtualHardwareSection);
|
||||
Assert.assertEquals("other26xLinux64Guest", guestOsPair.first());
|
||||
Assert.assertEquals("Other 2.6x Linux (64-bit)", guestOsPair.second());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMinimumHardwareVersion() throws IOException, SAXException, ParserConfigurationException {
|
||||
public void testGetMinimumHardwareVersion() throws IOException, SAXException {
|
||||
OVFVirtualHardwareSectionTO hardwareSection = ovfHelper.getVirtualHardwareSectionFromXmlString(ovfFileVirtualHardwareSection);
|
||||
Assert.assertEquals("vmx-08", hardwareSection.getMinimiumHardwareVersion());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,13 +20,10 @@
|
|||
package com.cloud.storage.template;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.naming.ConfigurationException;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import com.cloud.agent.api.to.OVFInformationTO;
|
||||
import com.cloud.agent.api.to.deployasis.OVFConfigurationTO;
|
||||
|
|
@ -50,7 +47,6 @@ import com.cloud.storage.StorageLayer;
|
|||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.component.AdapterBase;
|
||||
import com.cloud.utils.script.Script;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* processes the content of an OVA for registration of a template
|
||||
|
|
@ -107,7 +103,7 @@ public class OVAProcessor extends AdapterBase implements Processor {
|
|||
private void validateOva(String templateFileFullPath, FormatInfo info) throws InternalErrorException {
|
||||
String ovfFilePath = getOVFFilePath(templateFileFullPath);
|
||||
OVFHelper ovfHelper = new OVFHelper();
|
||||
Document doc = ovfHelper.getDocumentFromFile(ovfFilePath);
|
||||
Document doc = ovfHelper.getOvfParser().parseOVFFile(ovfFilePath);
|
||||
|
||||
OVFInformationTO ovfInformationTO = createOvfInformationTO(ovfHelper, doc, ovfFilePath);
|
||||
info.ovfInformationTO = ovfInformationTO;
|
||||
|
|
@ -235,15 +231,15 @@ public class OVAProcessor extends AdapterBase implements Processor {
|
|||
String templateFileFullPath = templatePath.endsWith(File.separator) ? templatePath : templatePath + File.separator;
|
||||
templateFileFullPath += templateName.endsWith(ImageFormat.OVA.getFileExtension()) ? templateName : templateName + "." + ImageFormat.OVA.getFileExtension();
|
||||
String ovfFileName = getOVFFilePath(templateFileFullPath);
|
||||
OVFHelper ovfHelper = new OVFHelper();
|
||||
if (ovfFileName == null) {
|
||||
String msg = "Unable to locate OVF file in template package directory: " + templatePath;
|
||||
LOGGER.error(msg);
|
||||
throw new InternalErrorException(msg);
|
||||
}
|
||||
try {
|
||||
Document ovfDoc = null;
|
||||
ovfDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File(ovfFileName));
|
||||
NodeList diskElements = new OVFHelper().getElementsByTagNameAndPrefix(ovfDoc, "Disk", "ovf");
|
||||
Document ovfDoc = ovfHelper.getOvfParser().parseOVFFile(ovfFileName);
|
||||
NodeList diskElements = ovfHelper.getOvfParser().getElementsFromOVFDocument(ovfDoc, "Disk");
|
||||
for (int i = 0; i < diskElements.getLength(); i++) {
|
||||
Element disk = (Element)diskElements.item(i);
|
||||
String diskSizeValue = disk.getAttribute("ovf:capacity");
|
||||
|
|
@ -262,7 +258,7 @@ public class OVAProcessor extends AdapterBase implements Processor {
|
|||
virtualSize += diskSize;
|
||||
}
|
||||
return virtualSize;
|
||||
} catch (InternalErrorException | IOException | NumberFormatException | ParserConfigurationException | SAXException e) {
|
||||
} catch (InternalErrorException | NumberFormatException e) {
|
||||
String msg = "getTemplateVirtualSize: Unable to parse OVF XML document " + templatePath + " to get the virtual disk " + templateName + " size due to " + e;
|
||||
LOGGER.error(msg);
|
||||
throw new InternalErrorException(msg);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
package org.apache.cloudstack.storage.command;
|
||||
|
||||
import com.cloud.agent.api.Answer;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.agent.api.to.OVFInformationTO;
|
||||
|
||||
public class UploadStatusAnswer extends Answer {
|
||||
public static enum UploadStatus {
|
||||
|
|
@ -32,8 +32,7 @@ public class UploadStatusAnswer extends Answer {
|
|||
private long physicalSize = 0;
|
||||
private String installPath = null;
|
||||
private int downloadPercent = 0;
|
||||
private Pair<String, String> guestOsInfo;
|
||||
private String minimumHardwareVersion;
|
||||
private OVFInformationTO ovfInformationTO;
|
||||
|
||||
protected UploadStatusAnswer() {
|
||||
}
|
||||
|
|
@ -89,19 +88,11 @@ public class UploadStatusAnswer extends Answer {
|
|||
this.downloadPercent = downloadPercent;
|
||||
}
|
||||
|
||||
public Pair<String, String> getGuestOsInfo() {
|
||||
return guestOsInfo;
|
||||
public OVFInformationTO getOvfInformationTO() {
|
||||
return ovfInformationTO;
|
||||
}
|
||||
|
||||
public void setGuestOsInfo(Pair<String, String> guestOsInfo) {
|
||||
this.guestOsInfo = guestOsInfo;
|
||||
}
|
||||
|
||||
public void setMinimumHardwareVersion(String minimumHardwareVersion) {
|
||||
this.minimumHardwareVersion = minimumHardwareVersion;
|
||||
}
|
||||
|
||||
public String getMinimumHardwareVersion() {
|
||||
return minimumHardwareVersion;
|
||||
public void setOvfInformationTO(OVFInformationTO ovfInformationTO) {
|
||||
this.ovfInformationTO = ovfInformationTO;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import org.junit.runner.RunWith;
|
|||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.powermock.api.mockito.PowerMockito;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
|
||||
|
|
@ -38,6 +39,7 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PowerMockIgnore({"javax.xml.*", "java.xml.*", "javax.management.*", "org.apache.xerces.*"})
|
||||
@PrepareForTest(OVAProcessor.class)
|
||||
public class OVAProcessorTest {
|
||||
OVAProcessor processor;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import java.util.stream.Collectors;
|
|||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.agent.api.to.NfsTO;
|
||||
import com.cloud.agent.api.to.OVFInformationTO;
|
||||
import com.cloud.storage.DataStoreRole;
|
||||
import com.cloud.storage.Upload;
|
||||
import org.apache.cloudstack.storage.image.deployasis.DeployAsIsHelper;
|
||||
|
|
@ -207,8 +208,9 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
|||
TemplateDataStoreVO tmpltStoreVO = _templateStoreDao.findByStoreTemplate(store.getId(), obj.getId());
|
||||
if (tmpltStoreVO != null) {
|
||||
if (tmpltStoreVO.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) {
|
||||
if (template.isDeployAsIs()) {
|
||||
boolean persistDeployAsIs = deployAsIsHelper.persistTemplateDeployAsIsDetails(template.getId(), answer, tmpltStoreVO);
|
||||
if (template.isDeployAsIs() && answer != null) {
|
||||
OVFInformationTO ovfInformationTO = answer.getOvfInformationTO();
|
||||
boolean persistDeployAsIs = deployAsIsHelper.persistTemplateOVFInformationAndUpdateGuestOS(template.getId(), ovfInformationTO, tmpltStoreVO);
|
||||
if (!persistDeployAsIs) {
|
||||
LOGGER.info("Failed persisting deploy-as-is template details for template " + template.getName());
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
package org.apache.cloudstack.storage.image.deployasis;
|
||||
|
||||
import com.cloud.agent.api.storage.DownloadAnswer;
|
||||
import com.cloud.agent.api.to.NicTO;
|
||||
import com.cloud.agent.api.to.OVFInformationTO;
|
||||
import com.cloud.agent.api.to.deployasis.OVFConfigurationTO;
|
||||
|
|
@ -100,41 +99,44 @@ public class DeployAsIsHelperImpl implements DeployAsIsHelper {
|
|||
gson = builder.create();
|
||||
}
|
||||
|
||||
public boolean persistTemplateDeployAsIsDetails(long templateId, DownloadAnswer answer, TemplateDataStoreVO tmpltStoreVO) {
|
||||
try {
|
||||
OVFInformationTO ovfInformationTO = answer.getOvfInformationTO();
|
||||
if (ovfInformationTO != null) {
|
||||
List<OVFPropertyTO> ovfProperties = ovfInformationTO.getProperties();
|
||||
List<OVFNetworkTO> networkRequirements = ovfInformationTO.getNetworks();
|
||||
OVFVirtualHardwareSectionTO ovfHardwareSection = ovfInformationTO.getHardwareSection();
|
||||
List<OVFEulaSectionTO> eulaSections = ovfInformationTO.getEulaSections();
|
||||
Pair<String, String> guestOsInfo = ovfInformationTO.getGuestOsInfo();
|
||||
private void persistTemplateOVFInformation(long templateId, OVFInformationTO ovfInformationTO) {
|
||||
List<OVFPropertyTO> ovfProperties = ovfInformationTO.getProperties();
|
||||
List<OVFNetworkTO> networkRequirements = ovfInformationTO.getNetworks();
|
||||
OVFVirtualHardwareSectionTO ovfHardwareSection = ovfInformationTO.getHardwareSection();
|
||||
List<OVFEulaSectionTO> eulaSections = ovfInformationTO.getEulaSections();
|
||||
Pair<String, String> guestOsInfo = ovfInformationTO.getGuestOsInfo();
|
||||
|
||||
if (CollectionUtils.isNotEmpty(ovfProperties)) {
|
||||
persistTemplateDeployAsIsInformationTOList(templateId, ovfProperties);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(networkRequirements)) {
|
||||
persistTemplateDeployAsIsInformationTOList(templateId, networkRequirements);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(eulaSections)) {
|
||||
persistTemplateDeployAsIsInformationTOList(templateId, eulaSections);
|
||||
}
|
||||
String minimumHardwareVersion = null;
|
||||
if (ovfHardwareSection != null) {
|
||||
if (CollectionUtils.isNotEmpty(ovfHardwareSection.getConfigurations())) {
|
||||
persistTemplateDeployAsIsInformationTOList(templateId, ovfHardwareSection.getConfigurations());
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(ovfHardwareSection.getCommonHardwareItems())) {
|
||||
persistTemplateDeployAsIsInformationTOList(templateId, ovfHardwareSection.getCommonHardwareItems());
|
||||
}
|
||||
minimumHardwareVersion = ovfHardwareSection.getMinimiumHardwareVersion();
|
||||
}
|
||||
if (guestOsInfo != null) {
|
||||
String osType = guestOsInfo.first();
|
||||
String osDescription = guestOsInfo.second();
|
||||
LOGGER.info("Guest OS information retrieved from the template: " + osType + " - " + osDescription);
|
||||
handleGuestOsFromOVFDescriptor(templateId, osType, osDescription, minimumHardwareVersion);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(ovfProperties)) {
|
||||
persistTemplateDeployAsIsInformationTOList(templateId, ovfProperties);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(networkRequirements)) {
|
||||
persistTemplateDeployAsIsInformationTOList(templateId, networkRequirements);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(eulaSections)) {
|
||||
persistTemplateDeployAsIsInformationTOList(templateId, eulaSections);
|
||||
}
|
||||
String minimumHardwareVersion = null;
|
||||
if (ovfHardwareSection != null) {
|
||||
if (CollectionUtils.isNotEmpty(ovfHardwareSection.getConfigurations())) {
|
||||
persistTemplateDeployAsIsInformationTOList(templateId, ovfHardwareSection.getConfigurations());
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(ovfHardwareSection.getCommonHardwareItems())) {
|
||||
persistTemplateDeployAsIsInformationTOList(templateId, ovfHardwareSection.getCommonHardwareItems());
|
||||
}
|
||||
minimumHardwareVersion = ovfHardwareSection.getMinimiumHardwareVersion();
|
||||
}
|
||||
if (guestOsInfo != null) {
|
||||
String osType = guestOsInfo.first();
|
||||
String osDescription = guestOsInfo.second();
|
||||
LOGGER.info("Guest OS information retrieved from the template: " + osType + " - " + osDescription);
|
||||
handleGuestOsFromOVFDescriptor(templateId, osType, osDescription, minimumHardwareVersion);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean persistTemplateOVFInformationAndUpdateGuestOS(long templateId, OVFInformationTO ovfInformationTO, TemplateDataStoreVO tmpltStoreVO) {
|
||||
try {
|
||||
if (ovfInformationTO != null) {
|
||||
persistTemplateOVFInformation(templateId, ovfInformationTO);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Error persisting deploy-as-is details for template " + templateId, e);
|
||||
|
|
@ -151,7 +153,7 @@ public class DeployAsIsHelperImpl implements DeployAsIsHelper {
|
|||
/**
|
||||
* Returns the mapped guest OS from the OVF file of the template to the CloudStack database OS ID
|
||||
*/
|
||||
public Long retrieveTemplateGuestOsIdFromGuestOsInfo(long templateId, String guestOsType, String guestOsDescription,
|
||||
private Long retrieveTemplateGuestOsIdFromGuestOsInfo(long templateId, String guestOsType, String guestOsDescription,
|
||||
String minimumHardwareVersion) {
|
||||
VMTemplateVO template = templateDao.findById(templateId);
|
||||
Hypervisor.HypervisorType hypervisor = template.getHypervisorType();
|
||||
|
|
@ -337,7 +339,7 @@ public class DeployAsIsHelperImpl implements DeployAsIsHelper {
|
|||
return map;
|
||||
}
|
||||
|
||||
private void persistTemplateDeployAsIsInformationTOList(long templateId,
|
||||
public void persistTemplateDeployAsIsInformationTOList(long templateId,
|
||||
List<? extends TemplateDeployAsIsInformationTO> informationTOList) {
|
||||
for (TemplateDeployAsIsInformationTO informationTO : informationTOList) {
|
||||
String propKey = getKeyFromInformationTO(informationTO);
|
||||
|
|
|
|||
|
|
@ -25,8 +25,7 @@ import java.util.concurrent.TimeUnit;
|
|||
import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import com.cloud.hypervisor.Hypervisor;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.agent.api.to.OVFInformationTO;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
|
||||
|
|
@ -412,18 +411,14 @@ public class ImageStoreUploadMonitorImpl extends ManagerBase implements ImageSto
|
|||
|
||||
VMTemplateVO templateUpdate = _templateDao.createForUpdate();
|
||||
templateUpdate.setSize(answer.getVirtualSize());
|
||||
if (template.getHypervisorType() == Hypervisor.HypervisorType.VMware) {
|
||||
Pair<String, String> guestOsInfo = answer.getGuestOsInfo();
|
||||
String minimumHardwareVersion = answer.getMinimumHardwareVersion();
|
||||
String osType = guestOsInfo.first();
|
||||
String osDescription = guestOsInfo.second();
|
||||
s_logger.info("Guest OS information retrieved from the template: " + osType + " - " + osDescription);
|
||||
try {
|
||||
Long guestOsId = deployAsIsHelper.retrieveTemplateGuestOsIdFromGuestOsInfo(template.getId(),
|
||||
osType, osDescription, minimumHardwareVersion);
|
||||
templateUpdate.setGuestOSId(guestOsId);
|
||||
} catch (CloudRuntimeException e) {
|
||||
s_logger.error("Could not map the guest OS to a CloudStack guest OS", e);
|
||||
|
||||
OVFInformationTO ovfInformationTO = answer.getOvfInformationTO();
|
||||
if (template.isDeployAsIs() && ovfInformationTO != null) {
|
||||
s_logger.debug("Received OVF information from the uploaded template");
|
||||
boolean persistDeployAsIs = deployAsIsHelper.persistTemplateOVFInformationAndUpdateGuestOS(tmpTemplate.getId(), ovfInformationTO, tmpTemplateDataStore);
|
||||
if (!persistDeployAsIs) {
|
||||
s_logger.info("Failed persisting deploy-as-is template details for template " + template.getName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
_templateDao.update(tmpTemplate.getId(), templateUpdate);
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@
|
|||
// under the License.
|
||||
package org.apache.cloudstack.storage.image.deployasis;
|
||||
|
||||
import com.cloud.agent.api.storage.DownloadAnswer;
|
||||
import com.cloud.agent.api.to.NicTO;
|
||||
import com.cloud.agent.api.to.OVFInformationTO;
|
||||
import com.cloud.vm.VirtualMachineProfile;
|
||||
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
|
||||
|
||||
|
|
@ -25,9 +25,7 @@ import java.util.Map;
|
|||
|
||||
public interface DeployAsIsHelper {
|
||||
|
||||
boolean persistTemplateDeployAsIsDetails(long templateId, DownloadAnswer answer, TemplateDataStoreVO tmpltStoreVO);
|
||||
boolean persistTemplateOVFInformationAndUpdateGuestOS(long templateId, OVFInformationTO ovfInformationTO, TemplateDataStoreVO tmpltStoreVO);
|
||||
Map<String, String> getVirtualMachineDeployAsIsProperties(VirtualMachineProfile vmId);
|
||||
Map<Integer, String> getAllocatedVirtualMachineNicsAdapterMapping(VirtualMachineProfile vm, NicTO[] nics);
|
||||
Long retrieveTemplateGuestOsIdFromGuestOsInfo(long templateId, String guestOsType, String guestOsDescription,
|
||||
String minimumHardwareVersion);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2278,8 +2278,9 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
|
|||
answer.setInstallPath(uploadEntity.getTmpltPath());
|
||||
answer.setPhysicalSize(uploadEntity.getPhysicalSize());
|
||||
answer.setDownloadPercent(100);
|
||||
answer.setGuestOsInfo(uploadEntity.getGuestOsInfo());
|
||||
answer.setMinimumHardwareVersion(uploadEntity.getMinimumHardwareVersion());
|
||||
if (uploadEntity.getOvfInformationTO() != null) {
|
||||
answer.setOvfInformationTO(uploadEntity.getOvfInformationTO());
|
||||
}
|
||||
uploadEntityStateMap.remove(entityUuid);
|
||||
return answer;
|
||||
} else if (uploadEntity.getUploadState() == UploadEntity.Status.IN_PROGRESS) {
|
||||
|
|
@ -3422,12 +3423,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
|
|||
uploadEntity.setVirtualSize(info.virtualSize);
|
||||
uploadEntity.setPhysicalSize(info.size);
|
||||
if (info.ovfInformationTO != null) {
|
||||
if (info.ovfInformationTO.getGuestOsInfo() != null) {
|
||||
uploadEntity.setGuestOsInfo(info.ovfInformationTO.getGuestOsInfo());
|
||||
}
|
||||
if (info.ovfInformationTO.getHardwareSection() != null) {
|
||||
uploadEntity.setMinimumHardwareVersion(info.ovfInformationTO.getHardwareSection().getMinimiumHardwareVersion());
|
||||
}
|
||||
uploadEntity.setOvfInformationTO(info.ovfInformationTO);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@
|
|||
package org.apache.cloudstack.storage.template;
|
||||
|
||||
|
||||
import com.cloud.agent.api.to.OVFInformationTO;
|
||||
import com.cloud.storage.Storage;
|
||||
import com.cloud.utils.Pair;
|
||||
|
||||
public class UploadEntity {
|
||||
private long downloadedsize;
|
||||
|
|
@ -36,8 +36,7 @@ public class UploadEntity {
|
|||
private String description;
|
||||
private long contentLength;
|
||||
private long processTimeout;
|
||||
private Pair<String, String> guestOsInfo;
|
||||
private String minimumHardwareVersion;
|
||||
private OVFInformationTO ovfInformationTO;
|
||||
|
||||
public static enum ResourceType {
|
||||
VOLUME, TEMPLATE
|
||||
|
|
@ -211,19 +210,11 @@ public class UploadEntity {
|
|||
this.contentLength = contentLength;
|
||||
}
|
||||
|
||||
public Pair<String, String> getGuestOsInfo() {
|
||||
return guestOsInfo;
|
||||
public OVFInformationTO getOvfInformationTO() {
|
||||
return ovfInformationTO;
|
||||
}
|
||||
|
||||
public void setGuestOsInfo(Pair<String, String> guestOsInfo) {
|
||||
this.guestOsInfo = guestOsInfo;
|
||||
}
|
||||
|
||||
public void setMinimumHardwareVersion(String minimumHardwareVersion) {
|
||||
this.minimumHardwareVersion = minimumHardwareVersion;
|
||||
}
|
||||
|
||||
public String getMinimumHardwareVersion() {
|
||||
return minimumHardwareVersion;
|
||||
public void setOvfInformationTO(OVFInformationTO ovfInformationTO) {
|
||||
this.ovfInformationTO = ovfInformationTO;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3334,6 +3334,7 @@
|
|||
"message.success.update.iprange": "Successfully updated IP range",
|
||||
"message.success.update.kubeversion": "Successfully updated Kubernetes supported version",
|
||||
"message.success.update.network": "Successfully updated Network",
|
||||
"message.success.update.template": "Successfully updated Template",
|
||||
"message.success.update.user": "Successfully updated user",
|
||||
"message.success.upgrade.kubernetes": "Successfully upgraded Kubernetes cluster",
|
||||
"message.success.upload": "Upload Successfully",
|
||||
|
|
@ -3351,6 +3352,7 @@
|
|||
"message.template.desc": "OS image that can be used to boot VMs",
|
||||
"message.template.import.vm.temporary": "If a temporary template is used, reset VM operation will not work after import.",
|
||||
"message.template.iso": "Please select a template or ISO to continue",
|
||||
"message.template.type.change.warning": "WARNING: Changing the template type to SYSTEM will disable further changes to the template.",
|
||||
"message.tier.required": "Tier is required",
|
||||
"message.tooltip.dns.1": "Name of a DNS server for use by VMs in the zone. The public IP addresses for the zone must have a route to this server.",
|
||||
"message.tooltip.dns.2": "A second DNS server name for use by VMs in the zone. The public IP addresses for the zone must have a route to this server.",
|
||||
|
|
|
|||
|
|
@ -103,18 +103,8 @@ export default {
|
|||
record.templatetype !== 'SYSTEM' &&
|
||||
record.isready
|
||||
},
|
||||
args: (record, store) => {
|
||||
var fields = ['name', 'displaytext', 'passwordenabled', 'ostypeid', 'isdynamicallyscalable']
|
||||
if (['Admin'].includes(store.userInfo.roletype)) {
|
||||
fields.push('templatetype')
|
||||
}
|
||||
return fields
|
||||
},
|
||||
mapping: {
|
||||
templatetype: {
|
||||
options: ['BUILTIN', 'USER', 'SYSTEM', 'ROUTING']
|
||||
}
|
||||
}
|
||||
popup: true,
|
||||
component: () => import('@/views/image/UpdateTemplate.vue')
|
||||
},
|
||||
{
|
||||
api: 'updateTemplatePermissions',
|
||||
|
|
|
|||
|
|
@ -1779,7 +1779,7 @@ export default {
|
|||
const vm = result.jobresult.virtualmachine
|
||||
const name = vm.displayname || vm.name || vm.id
|
||||
if (vm.password) {
|
||||
this.$notification.error({
|
||||
this.$notification.success({
|
||||
message: password + ` ${this.$t('label.for')} ` + name,
|
||||
description: vm.password,
|
||||
duration: 0
|
||||
|
|
|
|||
|
|
@ -0,0 +1,396 @@
|
|||
// 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.
|
||||
|
||||
<template>
|
||||
<div class="form-layout" v-ctrl-enter="handleSubmit">
|
||||
<a-spin :spinning="loading">
|
||||
<a-form
|
||||
:form="form"
|
||||
@submit="handleSubmit"
|
||||
layout="vertical">
|
||||
<a-form-item>
|
||||
<tooltip-label slot="label" :title="$t('label.name')" :tooltip="apiParams.name.description"/>
|
||||
<a-input
|
||||
v-decorator="['name', {
|
||||
rules: [{ required: true, message: `${$t('message.error.required.input')}` }]
|
||||
}]"
|
||||
:placeholder="apiParams.name.description"
|
||||
autoFocus />
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<tooltip-label slot="label" :title="$t('label.displaytext')" :tooltip="apiParams.displaytext.description"/>
|
||||
<a-input
|
||||
v-decorator="['displaytext', {
|
||||
rules: [{ required: true, message: `${$t('message.error.required.input')}` }]
|
||||
}]"
|
||||
:placeholder="apiParams.displaytext.description"
|
||||
autoFocus />
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<tooltip-label slot="label" :title="$t('label.passwordenabled')" :tooltip="apiParams.passwordenabled.description"/>
|
||||
<a-switch v-decorator="['passwordenabled', {}]" />
|
||||
</a-form-item>
|
||||
|
||||
<a-row :gutter="12" v-if="['KVM', 'VMware'].includes(resource.hypervisor)">
|
||||
<a-col :md="24" :lg="resource.hypervisor === 'KVM' ? 24 : 12" v-if="resource.hypervisor === 'KVM' || (resource.hypervisor === 'VMware' && !resource.deployasis)">
|
||||
<a-form-item :label="$t('label.rootdiskcontrollertype')">
|
||||
<a-select
|
||||
v-decorator="['rootDiskController', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: `${this.$t('message.error.select')}`
|
||||
}
|
||||
]
|
||||
}]"
|
||||
:loading="rootDisk.loading"
|
||||
:placeholder="$t('label.rootdiskcontrollertype')">
|
||||
<a-select-option v-for="opt in rootDisk.opts" :key="opt.id">
|
||||
{{ opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :md="24" :lg="12" v-if="resource.hypervisor === 'VMware' && !resource.deployasis">
|
||||
<a-form-item :label="$t('label.nicadaptertype')">
|
||||
<a-select
|
||||
v-decorator="['nicAdapter', {
|
||||
rules: [
|
||||
{
|
||||
required: false,
|
||||
message: `${this.$t('message.error.select')}`
|
||||
}
|
||||
]
|
||||
}]"
|
||||
:placeholder="$t('label.nicadaptertype')">
|
||||
<a-select-option v-for="opt in nicAdapterType.opts" :key="opt.id">
|
||||
{{ opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="12" v-if="resource.hypervisor !== 'VMware' || (resource.hypervisor === 'VMware' && !resource.deployasis)">
|
||||
<a-col :md="24" :lg="24">
|
||||
<a-form-item v-if="resource.hypervisor === 'VMware' && !resource.deployasis" :label="$t('label.keyboardtype')">
|
||||
<a-select
|
||||
v-decorator="['keyboard']"
|
||||
:placeholder="$t('label.keyboard')">
|
||||
<a-select-option v-for="opt in keyboardType.opts" :key="opt.id">
|
||||
{{ opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :md="24" :lg="24">
|
||||
<a-form-item :label="$t('label.ostypeid')">
|
||||
<a-select
|
||||
showSearch
|
||||
optionFilterProp="children"
|
||||
:filterOption="(input, option) => {
|
||||
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
v-decorator="['ostypeid', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: `${this.$t('message.error.select')}`
|
||||
}
|
||||
]
|
||||
}]"
|
||||
:loading="osTypes.loading"
|
||||
:placeholder="apiParams.ostypeid.description">
|
||||
<a-select-option v-for="opt in osTypes.opts" :key="opt.id">
|
||||
{{ opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-form-item>
|
||||
<tooltip-label slot="label" :title="$t('label.isdynamicallyscalable')" :tooltip="apiParams.isdynamicallyscalable.description"/>
|
||||
<a-switch v-decorator="['isdynamicallyscalable', {}]" />
|
||||
</a-form-item>
|
||||
<a-form-item v-if="isAdmin">
|
||||
<tooltip-label slot="label" :title="$t('label.templatetype')" :tooltip="apiParams.templatetype.description"/>
|
||||
<span v-if="selectedTemplateType ==='SYSTEM'">
|
||||
<a-alert type="warning">
|
||||
<span slot="message" v-html="$t('message.template.type.change.warning')" />
|
||||
</a-alert>
|
||||
<br/>
|
||||
</span>
|
||||
<a-select
|
||||
showSearch
|
||||
optionFilterProp="children"
|
||||
:filterOption="(input, option) => {
|
||||
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
v-decorator="['templatetype']"
|
||||
:placeholder="apiParams.templatetype.description"
|
||||
@change="val => { selectedTemplateType = val }">
|
||||
<a-select-option v-for="opt in templatetypes" :key="opt">
|
||||
{{ opt }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<div :span="24" class="action-button">
|
||||
<a-button @click="closeAction">{{ this.$t('label.cancel') }}</a-button>
|
||||
<a-button :loading="loading" ref="submit" type="primary" @click="handleSubmit">{{ this.$t('label.ok') }}</a-button>
|
||||
</div>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { api } from '@/api'
|
||||
import TooltipLabel from '@/components/widgets/TooltipLabel'
|
||||
|
||||
export default {
|
||||
name: 'UpdateTemplate',
|
||||
components: {
|
||||
TooltipLabel
|
||||
},
|
||||
props: {
|
||||
resource: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
templatetypes: ['BUILTIN', 'USER', 'SYSTEM', 'ROUTING'],
|
||||
rootDisk: {},
|
||||
nicAdapterType: {},
|
||||
keyboardType: {},
|
||||
osTypes: {},
|
||||
loading: false,
|
||||
selectedTemplateType: ''
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
this.form = this.$form.createForm(this)
|
||||
this.apiParams = this.$getApiParams('updateTemplate')
|
||||
this.isAdmin = ['Admin'].includes(this.$store.getters.userInfo.roletype)
|
||||
},
|
||||
created () {
|
||||
this.$set(this.rootDisk, 'loading', false)
|
||||
this.$set(this.rootDisk, 'opts', [])
|
||||
this.$set(this.nicAdapterType, 'loading', false)
|
||||
this.$set(this.nicAdapterType, 'opts', [])
|
||||
this.$set(this.keyboardType, 'loading', false)
|
||||
this.$set(this.keyboardType, 'opts', [])
|
||||
this.$set(this.osTypes, 'loading', false)
|
||||
this.$set(this.osTypes, 'opts', [])
|
||||
const resourceFields = ['name', 'displaytext', 'passwordenabled', 'ostypeid', 'isdynamicallyscalable']
|
||||
if (this.isAdmin) {
|
||||
resourceFields.push('templatetype')
|
||||
}
|
||||
for (var field of resourceFields) {
|
||||
var fieldValue = this.resource[field]
|
||||
if (fieldValue) {
|
||||
this.form.getFieldDecorator(field, { initialValue: fieldValue })
|
||||
}
|
||||
}
|
||||
const resourceDetailsFields = []
|
||||
if (this.resource.hypervisor === 'KVM') {
|
||||
resourceDetailsFields.push('rootDiskController')
|
||||
} else if (this.resource.hypervisor === 'VMware' && !this.resource.deployasis) {
|
||||
resourceDetailsFields.push(...['rootDiskController', 'nicAdapter', 'keyboard'])
|
||||
}
|
||||
for (var detailsField of resourceDetailsFields) {
|
||||
var detailValue = this.resource?.details?.[detailsField] || null
|
||||
if (detailValue) {
|
||||
this.form.getFieldDecorator(detailsField, { initialValue: detailValue })
|
||||
}
|
||||
}
|
||||
this.fetchData()
|
||||
},
|
||||
methods: {
|
||||
fetchData () {
|
||||
this.fetchOsTypes()
|
||||
this.fetchRootDiskControllerTypes(this.resource.hypervisor)
|
||||
this.fetchNicAdapterTypes()
|
||||
this.fetchKeyboardTypes()
|
||||
},
|
||||
isValidValueForKey (obj, key) {
|
||||
return key in obj && obj[key] != null && obj[key] !== undefined && obj[key] !== ''
|
||||
},
|
||||
fetchOsTypes () {
|
||||
const params = {}
|
||||
params.listAll = true
|
||||
this.osTypes.opts = []
|
||||
this.osTypes.loading = true
|
||||
api('listOsTypes', params).then(json => {
|
||||
const listOsTypes = json.listostypesresponse.ostype
|
||||
this.$set(this.osTypes, 'opts', listOsTypes)
|
||||
}).finally(() => {
|
||||
this.osTypes.loading = false
|
||||
})
|
||||
},
|
||||
fetchRootDiskControllerTypes (hyperVisor) {
|
||||
const controller = []
|
||||
this.rootDisk.opts = []
|
||||
|
||||
if (hyperVisor === 'KVM') {
|
||||
controller.push({
|
||||
id: '',
|
||||
description: ''
|
||||
})
|
||||
controller.push({
|
||||
id: 'ide',
|
||||
description: 'ide'
|
||||
})
|
||||
controller.push({
|
||||
id: 'osdefault',
|
||||
description: 'osdefault'
|
||||
})
|
||||
controller.push({
|
||||
id: 'scsi',
|
||||
description: 'scsi'
|
||||
})
|
||||
controller.push({
|
||||
id: 'virtio',
|
||||
description: 'virtio'
|
||||
})
|
||||
} else if (hyperVisor === 'VMware') {
|
||||
controller.push({
|
||||
id: '',
|
||||
description: ''
|
||||
})
|
||||
controller.push({
|
||||
id: 'scsi',
|
||||
description: 'scsi'
|
||||
})
|
||||
controller.push({
|
||||
id: 'ide',
|
||||
description: 'ide'
|
||||
})
|
||||
controller.push({
|
||||
id: 'osdefault',
|
||||
description: 'osdefault'
|
||||
})
|
||||
controller.push({
|
||||
id: 'pvscsi',
|
||||
description: 'pvscsi'
|
||||
})
|
||||
controller.push({
|
||||
id: 'lsilogic',
|
||||
description: 'lsilogic'
|
||||
})
|
||||
controller.push({
|
||||
id: 'lsisas1068',
|
||||
description: 'lsilogicsas'
|
||||
})
|
||||
controller.push({
|
||||
id: 'buslogic',
|
||||
description: 'buslogic'
|
||||
})
|
||||
}
|
||||
|
||||
this.$set(this.rootDisk, 'opts', controller)
|
||||
},
|
||||
fetchNicAdapterTypes () {
|
||||
const nicAdapterType = []
|
||||
nicAdapterType.push({
|
||||
id: '',
|
||||
description: ''
|
||||
})
|
||||
nicAdapterType.push({
|
||||
id: 'E1000',
|
||||
description: 'E1000'
|
||||
})
|
||||
nicAdapterType.push({
|
||||
id: 'PCNet32',
|
||||
description: 'PCNet32'
|
||||
})
|
||||
nicAdapterType.push({
|
||||
id: 'Vmxnet2',
|
||||
description: 'Vmxnet2'
|
||||
})
|
||||
nicAdapterType.push({
|
||||
id: 'Vmxnet3',
|
||||
description: 'Vmxnet3'
|
||||
})
|
||||
|
||||
this.$set(this.nicAdapterType, 'opts', nicAdapterType)
|
||||
},
|
||||
fetchKeyboardTypes () {
|
||||
const keyboardType = []
|
||||
const keyboardOpts = this.$config.keyboardOptions || {}
|
||||
keyboardType.push({
|
||||
id: '',
|
||||
description: ''
|
||||
})
|
||||
|
||||
Object.keys(keyboardOpts).forEach(keyboard => {
|
||||
keyboardType.push({
|
||||
id: keyboard,
|
||||
description: this.$t(keyboardOpts[keyboard])
|
||||
})
|
||||
})
|
||||
|
||||
this.$set(this.keyboardType, 'opts', keyboardType)
|
||||
},
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
if (this.loading) return
|
||||
this.form.validateFields((err, values) => {
|
||||
if (err) {
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
const params = {
|
||||
id: this.resource.id
|
||||
}
|
||||
const detailsField = ['rootDiskController', 'nicAdapter', 'keyboard']
|
||||
for (const key in values) {
|
||||
if (!this.isValidValueForKey(values, key)) continue
|
||||
if (detailsField.includes(key)) {
|
||||
params['details[0].' + key] = values[key]
|
||||
continue
|
||||
}
|
||||
params[key] = values[key]
|
||||
}
|
||||
api('updateTemplate', params).then(json => {
|
||||
this.$message.success(`${this.$t('message.success.update.template')}: ${this.resource.name}`)
|
||||
this.$emit('refresh-data')
|
||||
this.closeAction()
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
})
|
||||
},
|
||||
closeAction () {
|
||||
this.$emit('close-action')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.form-layout {
|
||||
width: 60vw;
|
||||
|
||||
@media (min-width: 500px) {
|
||||
width: 450px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -75,7 +75,7 @@ import com.cloud.usage.parser.SecurityGroupUsageParser;
|
|||
import com.cloud.usage.parser.StorageUsageParser;
|
||||
import com.cloud.usage.parser.BackupUsageParser;
|
||||
import com.cloud.usage.parser.VMInstanceUsageParser;
|
||||
import com.cloud.usage.parser.VMSanpshotOnPrimaryParser;
|
||||
import com.cloud.usage.parser.VMSnapshotOnPrimaryParser;
|
||||
import com.cloud.usage.parser.VMSnapshotUsageParser;
|
||||
import com.cloud.usage.parser.VPNUserUsageParser;
|
||||
import com.cloud.usage.parser.VmDiskUsageParser;
|
||||
|
|
@ -958,13 +958,7 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna
|
|||
s_logger.debug("VM Snapshot usage successfully parsed? " + parsed + " (for account: " + account.getAccountName() + ", id: " + account.getId() + ")");
|
||||
}
|
||||
}
|
||||
parsed = VMSnapshotUsageParser.parse(account, currentStartDate, currentEndDate);
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
if (!parsed) {
|
||||
s_logger.debug("VM Snapshot usage successfully parsed? " + parsed + " (for account: " + account.getAccountName() + ", id: " + account.getId() + ")");
|
||||
}
|
||||
}
|
||||
parsed = VMSanpshotOnPrimaryParser.parse(account, currentStartDate, currentEndDate);
|
||||
parsed = VMSnapshotOnPrimaryParser.parse(account, currentStartDate, currentEndDate);
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
if (!parsed) {
|
||||
s_logger.debug("VM Snapshot on primary usage successfully parsed? " + parsed + " (for account: " + account.getAccountName() + ", id: " + account.getId() + ")");
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ import com.cloud.user.AccountVO;
|
|||
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
|
||||
|
||||
@Component
|
||||
public class VMSanpshotOnPrimaryParser {
|
||||
public static final Logger s_logger = Logger.getLogger(VMSanpshotOnPrimaryParser.class.getName());
|
||||
public class VMSnapshotOnPrimaryParser {
|
||||
public static final Logger s_logger = Logger.getLogger(VMSnapshotOnPrimaryParser.class.getName());
|
||||
|
||||
private static UsageDao s_usageDao;
|
||||
private static UsageVMSnapshotOnPrimaryDao s_usageSnapshotOnPrimaryDao;
|
||||
Loading…
Reference in New Issue