mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
[VMware] Full OVF properties support
This commit is contained in:
parent
8ee17e19a0
commit
d864e9dc39
@ -0,0 +1,61 @@
|
|||||||
|
//
|
||||||
|
// 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.util.List;
|
||||||
|
|
||||||
|
public class OVFConfigurationTO {
|
||||||
|
|
||||||
|
private final String id;
|
||||||
|
private final String label;
|
||||||
|
private final String description;
|
||||||
|
private List<OVFVirtualHardwareItemTO> hardwareItems;
|
||||||
|
private int index;
|
||||||
|
|
||||||
|
public OVFConfigurationTO(String id, String label, String description, int index) {
|
||||||
|
this.id = id;
|
||||||
|
this.label = label;
|
||||||
|
this.description = description;
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHardwareItems(List<OVFVirtualHardwareItemTO> items) {
|
||||||
|
this.hardwareItems = items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<OVFVirtualHardwareItemTO> getHardwareItems() {
|
||||||
|
return hardwareItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -16,18 +16,36 @@
|
|||||||
// specific language governing permissions and limitations
|
// specific language governing permissions and limitations
|
||||||
// under the License.
|
// under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
package com.cloud.agent.api.storage;
|
package com.cloud.agent.api.storage;
|
||||||
|
|
||||||
public interface OVFProperty {
|
import com.cloud.agent.api.LogLevel;
|
||||||
|
|
||||||
Long getTemplateId();
|
import java.io.Serializable;
|
||||||
String getKey();
|
|
||||||
String getType();
|
/**
|
||||||
String getValue();
|
* End-user licence agreement
|
||||||
String getQualifiers();
|
*/
|
||||||
Boolean isUserConfigurable();
|
public class OVFEulaSectionTO implements Serializable {
|
||||||
String getLabel();
|
private String info;
|
||||||
String getDescription();
|
@LogLevel(LogLevel.Log4jLevel.Off)
|
||||||
Boolean isPassword();
|
private byte[] compressedLicense;
|
||||||
|
private int index;
|
||||||
|
|
||||||
|
public OVFEulaSectionTO(String info, byte[] license, int eulaIndex) {
|
||||||
|
this.info = info;
|
||||||
|
this.compressedLicense = license;
|
||||||
|
this.index = eulaIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo() {
|
||||||
|
return this.info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getCompressedLicense() {
|
||||||
|
return this.compressedLicense;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -22,8 +22,15 @@ import java.io.PrintWriter;
|
|||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
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.DocumentBuilderFactory;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
import javax.xml.transform.Transformer;
|
import javax.xml.transform.Transformer;
|
||||||
@ -34,13 +41,20 @@ import javax.xml.transform.stream.StreamResult;
|
|||||||
|
|
||||||
import com.cloud.configuration.Resource.ResourceType;
|
import com.cloud.configuration.Resource.ResourceType;
|
||||||
import com.cloud.exception.InternalErrorException;
|
import com.cloud.exception.InternalErrorException;
|
||||||
|
import com.cloud.utils.compression.CompressionUtil;
|
||||||
|
import org.apache.cloudstack.api.net.NetworkPrerequisiteTO;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.commons.lang.math.NumberUtils;
|
import org.apache.commons.lang.math.NumberUtils;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.NamedNodeMap;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
import org.w3c.dom.NodeList;
|
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.InputSource;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
@ -73,10 +87,11 @@ public class OVFHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the text value of a node's child with name "childNodeName", null if not present
|
* Get the text value of a node's child with name or suffix "childNodeName", null if not present
|
||||||
* Example:
|
* Example:
|
||||||
* <Node>
|
* <Node>
|
||||||
* <childNodeName>Text value</childNodeName>
|
* <childNodeName>Text value</childNodeName>
|
||||||
|
* <rasd:childNodeName>Text value</rasd:childNodeName>
|
||||||
* </Node>
|
* </Node>
|
||||||
*/
|
*/
|
||||||
private String getChildNodeValue(Node node, String childNodeName) {
|
private String getChildNodeValue(Node node, String childNodeName) {
|
||||||
@ -84,7 +99,9 @@ public class OVFHelper {
|
|||||||
NodeList childNodes = node.getChildNodes();
|
NodeList childNodes = node.getChildNodes();
|
||||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||||
Node value = childNodes.item(i);
|
Node value = childNodes.item(i);
|
||||||
if (value != null && value.getNodeName().equals(childNodeName)) {
|
// 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 value.getTextContent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,93 +109,287 @@ public class OVFHelper {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
* Create OVFProperty class from the parsed node. Note that some fields may not be present.
|
||||||
* The key attribute is required
|
* The key attribute is required
|
||||||
*/
|
*/
|
||||||
protected OVFPropertyTO createOVFPropertyFromNode(Node node) {
|
protected OVFPropertyTO createOVFPropertyFromNode(Node node, int index, String category) {
|
||||||
Element property = (Element) node;
|
Element element = (Element) node;
|
||||||
String key = property.getAttribute("ovf:key");
|
String key = getNodeAttribute(element, "ovf","key");
|
||||||
if (StringUtils.isBlank(key)) {
|
if (StringUtils.isBlank(key)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String value = property.getAttribute("ovf:value");
|
String value = getNodeAttribute(element, "ovf","value");
|
||||||
String type = property.getAttribute("ovf:type");
|
String type = getNodeAttribute(element, "ovf","type");
|
||||||
String qualifiers = property.getAttribute("ovf:qualifiers");
|
String qualifiers = getNodeAttribute(element, "ovf","qualifiers");
|
||||||
String userConfigurableStr = property.getAttribute("ovf:userConfigurable");
|
String userConfigurableStr = getNodeAttribute(element, "ovf","userConfigurable");
|
||||||
boolean userConfigurable = StringUtils.isNotBlank(userConfigurableStr) &&
|
boolean userConfigurable = StringUtils.isNotBlank(userConfigurableStr) &&
|
||||||
userConfigurableStr.equalsIgnoreCase("true");
|
userConfigurableStr.equalsIgnoreCase("true");
|
||||||
String passStr = property.getAttribute("ovf:password");
|
String passStr = getNodeAttribute(element, "ovf","password");
|
||||||
boolean password = StringUtils.isNotBlank(passStr) && passStr.equalsIgnoreCase("true");
|
boolean password = StringUtils.isNotBlank(passStr) && passStr.equalsIgnoreCase("true");
|
||||||
String label = getChildNodeValue(node, "Label");
|
String label = getChildNodeValue(node, "Label");
|
||||||
String description = getChildNodeValue(node, "Description");
|
String description = getChildNodeValue(node, "Description");
|
||||||
return new OVFPropertyTO(key, type, value, qualifiers, userConfigurable, label, description, password);
|
s_logger.debug("Creating OVF property index " + index + (category == null ? "" : " for category " + category)
|
||||||
|
+ " with key = " + key);
|
||||||
|
return new OVFPropertyTO(key, type, value, qualifiers, userConfigurable,
|
||||||
|
label, description, password, index, category);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve OVF properties from a parsed OVF file, with attribute 'ovf:userConfigurable' set to true
|
* Retrieve OVF properties from a parsed OVF file including its category (if available) and in-order,
|
||||||
|
* with attribute 'ovf:userConfigurable' set to true.
|
||||||
*/
|
*/
|
||||||
private List<OVFPropertyTO> getConfigurableOVFPropertiesFromDocument(Document doc) {
|
public List<OVFPropertyTO> getConfigurableOVFPropertiesFromDocument(Document doc) {
|
||||||
List<OVFPropertyTO> props = new ArrayList<>();
|
List<OVFPropertyTO> props = new ArrayList<>();
|
||||||
NodeList properties = doc.getElementsByTagName("Property");
|
if (doc == null) {
|
||||||
if (properties != null) {
|
return props;
|
||||||
for (int i = 0; i < properties.getLength(); i++) {
|
}
|
||||||
Node node = properties.item(i);
|
int propertyIndex = 0;
|
||||||
|
NodeList productSections = doc.getElementsByTagName("ProductSection");
|
||||||
|
if (productSections != null) {
|
||||||
|
String lastCategoryFound = null;
|
||||||
|
for (int i = 0; i < productSections.getLength(); i++) {
|
||||||
|
Node node = productSections.item(i);
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
OVFPropertyTO prop = createOVFPropertyFromNode(node);
|
NodeList childNodes = node.getChildNodes();
|
||||||
|
for (int j = 0; j < childNodes.getLength(); j++) {
|
||||||
|
Node child = childNodes.item(j);
|
||||||
|
if (child == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (child.getNodeName().equalsIgnoreCase("Category")) {
|
||||||
|
lastCategoryFound = child.getTextContent();
|
||||||
|
s_logger.info("Category found " + lastCategoryFound);
|
||||||
|
} else if (child.getNodeName().equalsIgnoreCase("Property")) {
|
||||||
|
OVFPropertyTO prop = createOVFPropertyFromNode(child, propertyIndex, lastCategoryFound);
|
||||||
if (prop != null && prop.isUserConfigurable()) {
|
if (prop != null && prop.isUserConfigurable()) {
|
||||||
props.add(prop);
|
props.add(prop);
|
||||||
|
propertyIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return props;
|
return props;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get properties from OVF file located on ovfFilePath
|
|
||||||
*/
|
|
||||||
public List<OVFPropertyTO> getOVFPropertiesFromFile(String ovfFilePath) throws ParserConfigurationException, IOException, SAXException {
|
|
||||||
if (StringUtils.isBlank(ovfFilePath)) {
|
|
||||||
return new ArrayList<>();
|
|
||||||
}
|
|
||||||
File ovfFile = new File(ovfFilePath);
|
|
||||||
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(ovfFile);
|
|
||||||
return getConfigurableOVFPropertiesFromDocument(doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get properties from OVF XML string
|
* Get properties from OVF XML string
|
||||||
*/
|
*/
|
||||||
protected List<OVFPropertyTO> getOVFPropertiesXmlString(final String ovfFilePath) throws ParserConfigurationException, IOException, SAXException {
|
protected List<OVFPropertyTO> getOVFPropertiesFromXmlString(final String ovfString) throws ParserConfigurationException, IOException, SAXException {
|
||||||
InputSource is = new InputSource(new StringReader(ovfFilePath));
|
InputSource is = new InputSource(new StringReader(ovfString));
|
||||||
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
|
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
|
||||||
return getConfigurableOVFPropertiesFromDocument(doc);
|
return getConfigurableOVFPropertiesFromDocument(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DatadiskTO> getOVFVolumeInfo(final String ovfFilePath) {
|
protected List<OVFConfigurationTO> getOVFDeploymentOptionsFromXmlString(final String ovfString) throws ParserConfigurationException, IOException, SAXException {
|
||||||
if (StringUtils.isBlank(ovfFilePath)) {
|
InputSource is = new InputSource(new StringReader(ovfString));
|
||||||
return new ArrayList<DatadiskTO>();
|
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
|
||||||
|
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);
|
||||||
|
return getVirtualHardwareItemsFromDocumentTree(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);
|
||||||
|
return getEulaSectionsFromDocument(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DatadiskTO> getOVFVolumeInfoFromFile(final String ovfFilePath, final String configurationId) throws InternalErrorException {
|
||||||
|
if (StringUtils.isBlank(ovfFilePath)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
Document doc = getDocumentFromFile(ovfFilePath);
|
||||||
|
|
||||||
|
return getOVFVolumeInfoFromFile(ovfFilePath, doc, configurationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DatadiskTO> getOVFVolumeInfoFromFile(String ovfFilePath, Document doc, String configurationId) throws InternalErrorException {
|
||||||
|
if (org.apache.commons.lang.StringUtils.isBlank(ovfFilePath)) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
ArrayList<OVFFile> vf = new ArrayList<OVFFile>();
|
|
||||||
ArrayList<OVFDisk> vd = new ArrayList<OVFDisk>();
|
|
||||||
|
|
||||||
File ovfFile = new File(ovfFilePath);
|
File ovfFile = new File(ovfFilePath);
|
||||||
try {
|
List<OVFVirtualHardwareItemTO> hardwareItems = getVirtualHardwareItemsFromDocumentTree(doc);
|
||||||
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File(ovfFilePath));
|
List<OVFFile> files = extractFilesFromOvfDocumentTree(ovfFile, doc);
|
||||||
|
List<OVFDisk> disks = extractDisksFromOvfDocumentTree(doc);
|
||||||
|
|
||||||
|
List<OVFVirtualHardwareItemTO> diskHardwareItems = hardwareItems.stream()
|
||||||
|
.filter(x -> x.getResourceType() == OVFVirtualHardwareItemTO.HardwareResourceType.DiskDrive &&
|
||||||
|
hardwareItemContainsConfiguration(x, configurationId))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
List<DatadiskTO> diskTOs = matchHardwareItemsToDiskAndFilesInformation(diskHardwareItems, files, disks, ovfFile.getParent());
|
||||||
|
return diskTOs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String extractDiskIdFromDiskHostResource(String hostResource) {
|
||||||
|
if (hostResource.startsWith("ovf:/disk/")) {
|
||||||
|
return hostResource.replace("ovf:/disk/", "");
|
||||||
|
}
|
||||||
|
String[] resourceParts = hostResource.split("/");
|
||||||
|
return resourceParts[resourceParts.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
private OVFDisk getDiskDefinitionFromDiskId(String diskId, List<OVFDisk> disks) {
|
||||||
|
for (OVFDisk disk : disks) {
|
||||||
|
if (disk._diskId.equalsIgnoreCase(diskId)) {
|
||||||
|
return disk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<DatadiskTO> matchHardwareItemsToDiskAndFilesInformation(List<OVFVirtualHardwareItemTO> diskHardwareItems,
|
||||||
|
List<OVFFile> files, List<OVFDisk> disks,
|
||||||
|
String ovfParentPath) throws InternalErrorException {
|
||||||
|
List<DatadiskTO> diskTOs = new LinkedList<>();
|
||||||
|
int diskNumber = 0;
|
||||||
|
for (OVFVirtualHardwareItemTO diskItem : diskHardwareItems) {
|
||||||
|
if (StringUtils.isBlank(diskItem.getHostResource())) {
|
||||||
|
s_logger.error("Missing disk information for hardware item " + diskItem.getElementName() + " " + diskItem.getInstanceId());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String diskId = extractDiskIdFromDiskHostResource(diskItem.getHostResource());
|
||||||
|
OVFDisk diskDefinition = getDiskDefinitionFromDiskId(diskId, disks);
|
||||||
|
if (diskDefinition == null) {
|
||||||
|
s_logger.error("Missing disk definition for disk ID " + diskId);
|
||||||
|
}
|
||||||
|
OVFFile fileDefinition = getFileDefinitionFromDiskDefinition(diskDefinition._fileRef, files);
|
||||||
|
DatadiskTO datadiskTO = generateDiskTO(fileDefinition, diskDefinition, ovfParentPath, diskNumber, diskItem);
|
||||||
|
diskTOs.add(datadiskTO);
|
||||||
|
diskNumber++;
|
||||||
|
}
|
||||||
|
List<OVFFile> isoFiles = files.stream().filter(x -> x.isIso).collect(Collectors.toList());
|
||||||
|
for (OVFFile isoFile : isoFiles) {
|
||||||
|
DatadiskTO isoTO = generateDiskTO(isoFile, null, ovfParentPath, diskNumber, null);
|
||||||
|
diskTOs.add(isoTO);
|
||||||
|
diskNumber++;
|
||||||
|
}
|
||||||
|
return diskTOs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DatadiskTO generateDiskTO(OVFFile file, OVFDisk disk, String ovfParentPath, int diskNumber,
|
||||||
|
OVFVirtualHardwareItemTO diskItem) throws InternalErrorException {
|
||||||
|
String path = file != null ? ovfParentPath + File.separator + file._href : null;
|
||||||
|
if (StringUtils.isNotBlank(path)) {
|
||||||
|
File f = new File(path);
|
||||||
|
if (!f.exists() || f.isDirectory()) {
|
||||||
|
s_logger.error("One of the attached disk or iso does not exists " + path);
|
||||||
|
throw new InternalErrorException("One of the attached disk or iso as stated on OVF does not exists " + path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Long capacity = disk != null ? disk._capacity : file._size;
|
||||||
|
Long fileSize = file != null ? file._size : 0L;
|
||||||
|
|
||||||
|
String controller = "";
|
||||||
|
String controllerSubType = "";
|
||||||
|
if (disk != null) {
|
||||||
|
OVFDiskController cDiskController = disk._controller;
|
||||||
|
controller = cDiskController == null ? "" : disk._controller._name;
|
||||||
|
controllerSubType = cDiskController == null ? "" : disk._controller._subType;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isIso = file != null && file.isIso;
|
||||||
|
boolean bootable = file != null && file._bootable;
|
||||||
|
String diskId = disk == null ? file._id : disk._diskId;
|
||||||
|
String configuration = diskItem != null ? diskItem.getConfigurationIds() : null;
|
||||||
|
return new DatadiskTO(path, capacity, fileSize, diskId,
|
||||||
|
isIso, bootable, controller, controllerSubType, diskNumber, configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<OVFDisk> extractDisksFromOvfDocumentTree(Document doc) {
|
||||||
NodeList disks = doc.getElementsByTagName("Disk");
|
NodeList disks = doc.getElementsByTagName("Disk");
|
||||||
NodeList files = doc.getElementsByTagName("File");
|
NodeList ovfDisks = doc.getElementsByTagName("ovf:Disk");
|
||||||
NodeList items = doc.getElementsByTagName("Item");
|
NodeList items = doc.getElementsByTagName("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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disk == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
OVFDisk od = new OVFDisk();
|
||||||
|
String virtualSize = getNodeAttribute(disk, "ovf", "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"));
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
if (s_logger.isTraceEnabled()) {
|
||||||
|
s_logger.trace(String.format("found %d disk definitions",vd.size()));
|
||||||
|
}
|
||||||
|
return vd;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<OVFFile> extractFilesFromOvfDocumentTree(File ovfFile, Document doc) {
|
||||||
|
NodeList files = doc.getElementsByTagName("File");
|
||||||
|
ArrayList<OVFFile> vf = new ArrayList<>();
|
||||||
boolean toggle = true;
|
boolean toggle = true;
|
||||||
for (int j = 0; j < files.getLength(); j++) {
|
for (int j = 0; j < files.getLength(); j++) {
|
||||||
Element file = (Element)files.item(j);
|
Element file = (Element)files.item(j);
|
||||||
OVFFile of = new OVFFile();
|
OVFFile of = new OVFFile();
|
||||||
of._href = file.getAttribute("ovf:href");
|
of._href = getNodeAttribute(file,"ovf","href");
|
||||||
if (of._href.endsWith("vmdk") || of._href.endsWith("iso")) {
|
if (of._href.endsWith("vmdk") || of._href.endsWith("iso")) {
|
||||||
of._id = file.getAttribute("ovf:id");
|
of._id = getNodeAttribute(file,"ovf","id");
|
||||||
String size = file.getAttribute("ovf:size");
|
String size = getNodeAttribute(file,"ovf", "size");
|
||||||
if (StringUtils.isNotBlank(size)) {
|
if (StringUtils.isNotBlank(size)) {
|
||||||
of._size = Long.parseLong(size);
|
of._size = Long.parseLong(size);
|
||||||
} else {
|
} else {
|
||||||
@ -194,72 +405,24 @@ public class OVFHelper {
|
|||||||
vf.add(of);
|
vf.add(of);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < disks.getLength(); i++) {
|
if (s_logger.isTraceEnabled()) {
|
||||||
Element disk = (Element)disks.item(i);
|
s_logger.trace(String.format("found %d file definitions in %s",vf.size(), ovfFile.getPath()));
|
||||||
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 = NumberUtils.toLong(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;
|
return vf;
|
||||||
}
|
|
||||||
od._controller = getControllerType(items, od._diskId);
|
|
||||||
vd.add(od);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Document getDocumentFromFile(String ovfFilePath) {
|
||||||
|
if (org.apache.commons.lang.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) {
|
} catch (SAXException | IOException | ParserConfigurationException e) {
|
||||||
s_logger.error("Unexpected exception caught while parsing ovf file:" + ovfFilePath, e);
|
s_logger.error("Unexpected exception caught while parsing ovf file:" + ovfFilePath, e);
|
||||||
throw new CloudRuntimeException(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 = "";
|
|
||||||
String controllerSubType = "";
|
|
||||||
if (cdisk != null) {
|
|
||||||
OVFDiskController cDiskController = cdisk._controller;
|
|
||||||
controller = cDiskController == null ? "" : cdisk._controller._name;
|
|
||||||
controllerSubType = cDiskController == 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) {
|
private OVFDiskController getControllerType(final NodeList itemList, final String diskId) {
|
||||||
@ -330,19 +493,19 @@ public class OVFHelper {
|
|||||||
return dc;
|
return dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void rewriteOVFFile(final String origOvfFilePath, final String newOvfFilePath, final String diskName) {
|
public void rewriteOVFFileForSingleDisk(final String origOvfFilePath, final String newOvfFilePath, final String diskName) {
|
||||||
try {
|
final Document doc = getDocumentFromFile(origOvfFilePath);
|
||||||
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File(origOvfFilePath));
|
|
||||||
NodeList disks = doc.getElementsByTagName("Disk");
|
NodeList disks = doc.getElementsByTagName("Disk");
|
||||||
NodeList files = doc.getElementsByTagName("File");
|
NodeList files = doc.getElementsByTagName("File");
|
||||||
NodeList items = doc.getElementsByTagName("Item");
|
NodeList items = doc.getElementsByTagName("Item");
|
||||||
String keepfile = null;
|
String keepfile = null;
|
||||||
List<Element> toremove = new ArrayList<Element>();
|
List<Element> toremove = new ArrayList<>();
|
||||||
for (int j = 0; j < files.getLength(); j++) {
|
for (int j = 0; j < files.getLength(); j++) {
|
||||||
Element file = (Element)files.item(j);
|
Element file = (Element)files.item(j);
|
||||||
String href = file.getAttribute("ovf:href");
|
String href = getNodeAttribute(file,"ovf", "href");
|
||||||
if (diskName.equals(href)) {
|
if (diskName.equals(href)) {
|
||||||
keepfile = file.getAttribute("ovf:id");
|
keepfile = getNodeAttribute(file,"ovf","id");
|
||||||
} else {
|
} else {
|
||||||
toremove.add(file);
|
toremove.add(file);
|
||||||
}
|
}
|
||||||
@ -350,21 +513,21 @@ public class OVFHelper {
|
|||||||
String keepdisk = null;
|
String keepdisk = null;
|
||||||
for (int i = 0; i < disks.getLength(); i++) {
|
for (int i = 0; i < disks.getLength(); i++) {
|
||||||
Element disk = (Element)disks.item(i);
|
Element disk = (Element)disks.item(i);
|
||||||
String fileRef = disk.getAttribute("ovf:fileRef");
|
String fileRef = getNodeAttribute(disk,"ovf","fileRef");
|
||||||
if (keepfile == null) {
|
if (keepfile == null) {
|
||||||
s_logger.info("FATAL: OVA format error");
|
s_logger.info("FATAL: OVA format error");
|
||||||
} else if (keepfile.equals(fileRef)) {
|
} else if (keepfile.equals(fileRef)) {
|
||||||
keepdisk = disk.getAttribute("ovf:diskId");
|
keepdisk = getNodeAttribute(disk,"ovf","diskId");
|
||||||
} else {
|
} else {
|
||||||
toremove.add(disk);
|
toremove.add(disk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int k = 0; k < items.getLength(); k++) {
|
for (int k = 0; k < items.getLength(); k++) {
|
||||||
Element item = (Element)items.item(k);
|
Element item = (Element) items.item(k);
|
||||||
NodeList cn = item.getChildNodes();
|
NodeList cn = item.getChildNodes();
|
||||||
for (int l = 0; l < cn.getLength(); l++) {
|
for (int l = 0; l < cn.getLength(); l++) {
|
||||||
if (cn.item(l) instanceof Element) {
|
if (cn.item(l) instanceof Element) {
|
||||||
Element el = (Element)cn.item(l);
|
Element el = (Element) cn.item(l);
|
||||||
if ("rasd:HostResource".equals(el.getNodeName())
|
if ("rasd:HostResource".equals(el.getNodeName())
|
||||||
&& !(el.getTextContent().contains("ovf:/file/" + keepdisk) || el.getTextContent().contains("ovf:/disk/" + keepdisk))) {
|
&& !(el.getTextContent().contains("ovf:/file/" + keepdisk) || el.getTextContent().contains("ovf:/disk/" + keepdisk))) {
|
||||||
toremove.add(item);
|
toremove.add(item);
|
||||||
@ -380,6 +543,12 @@ public class OVFHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writeDocumentToFile(newOvfFilePath, doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeDocumentToFile(String newOvfFilePath, Document doc) {
|
||||||
|
try {
|
||||||
|
|
||||||
final StringWriter writer = new StringWriter();
|
final StringWriter writer = new StringWriter();
|
||||||
final StreamResult result = new StreamResult(writer);
|
final StreamResult result = new StreamResult(writer);
|
||||||
final TransformerFactory tf = TransformerFactory.newInstance();
|
final TransformerFactory tf = TransformerFactory.newInstance();
|
||||||
@ -389,21 +558,312 @@ public class OVFHelper {
|
|||||||
PrintWriter outfile = new PrintWriter(newOvfFilePath);
|
PrintWriter outfile = new PrintWriter(newOvfFilePath);
|
||||||
outfile.write(writer.toString());
|
outfile.write(writer.toString());
|
||||||
outfile.close();
|
outfile.close();
|
||||||
} catch (SAXException | IOException | ParserConfigurationException | TransformerException e) {
|
} catch (IOException | TransformerException e) {
|
||||||
s_logger.info("Unexpected exception caught while removing network elements from OVF:" + e.getMessage(), e);
|
s_logger.info("Unexpected exception caught while rewriting OVF:" + e.getMessage(), e);
|
||||||
throw new CloudRuntimeException(e);
|
throw new CloudRuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OVFDisk getDisk(String fileRef, List<OVFDisk> disks) {
|
OVFFile getFileDefinitionFromDiskDefinition(String fileRef, List<OVFFile> files) {
|
||||||
for (OVFDisk disk : disks) {
|
for (OVFFile file : files) {
|
||||||
if (disk._fileRef.equals(fileRef)) {
|
if (file._id.equals(fileRef)) {
|
||||||
return disk;
|
return file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<NetworkPrerequisiteTO> getNetPrerequisitesFromDocument(Document doc) throws InternalErrorException {
|
||||||
|
if (doc == null) {
|
||||||
|
if (s_logger.isTraceEnabled()) {
|
||||||
|
s_logger.trace("no document to parse; returning no prerequiste networks");
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, NetworkPrerequisiteTO> nets = getNetworksFromDocumentTree(doc);
|
||||||
|
|
||||||
|
checkForOnlyOneSystemNode(doc);
|
||||||
|
|
||||||
|
matchNicsToNets(nets, doc);
|
||||||
|
|
||||||
|
return new ArrayList<>(nets.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void matchNicsToNets(Map<String, NetworkPrerequisiteTO> nets, Node systemElement) {
|
||||||
|
final DocumentTraversal traversal = (DocumentTraversal) systemElement;
|
||||||
|
final NodeIterator iterator = traversal.createNodeIterator(systemElement, NodeFilter.SHOW_ELEMENT, null, true);
|
||||||
|
if (s_logger.isTraceEnabled()) {
|
||||||
|
s_logger.trace(String.format("starting out with %d network-prerequisites, parsing hardware",nets.size()));
|
||||||
|
}
|
||||||
|
int nicCount = 0;
|
||||||
|
for (Node n = iterator.nextNode(); n != null; n = iterator.nextNode()) {
|
||||||
|
final Element e = (Element) n;
|
||||||
|
if ("rasd:Connection".equals(e.getTagName())) {
|
||||||
|
nicCount++;
|
||||||
|
String name = e.getTextContent(); // should be in our nets
|
||||||
|
if(nets.get(name) == null) {
|
||||||
|
if(s_logger.isInfoEnabled()) {
|
||||||
|
s_logger.info(String.format("found a nic definition without a network definition byname %s, adding it to the list.", name));
|
||||||
|
}
|
||||||
|
nets.put(name, new NetworkPrerequisiteTO());
|
||||||
|
}
|
||||||
|
NetworkPrerequisiteTO thisNet = nets.get(name);
|
||||||
|
if (e.getParentNode() != null) {
|
||||||
|
fillNicPrerequisites(thisNet,e.getParentNode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (s_logger.isTraceEnabled()) {
|
||||||
|
s_logger.trace(String.format("ending up with %d network-prerequisites, parsed %d nics", nets.size(), nicCount));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get all the stuff from parent node
|
||||||
|
*
|
||||||
|
* @param nic the object to carry through the system
|
||||||
|
* @param parentNode the xml container node for nic data
|
||||||
|
*/
|
||||||
|
private void fillNicPrerequisites(NetworkPrerequisiteTO 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");
|
||||||
|
|
||||||
|
try {
|
||||||
|
int addressOnParent = Integer.parseInt(addressOnParentStr);
|
||||||
|
nic.setAddressOnParent(addressOnParent);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
s_logger.warn("Encountered element of type \"AddressOnParent\", that could not be parse to an integer number: " + addressOnParentStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean automaticAllocation = StringUtils.isNotBlank(automaticAllocationStr) && Boolean.parseBoolean(automaticAllocationStr);
|
||||||
|
nic.setAutomaticAllocation(automaticAllocation);
|
||||||
|
nic.setNicDescription(description);
|
||||||
|
nic.setElementName(elementName);
|
||||||
|
|
||||||
|
try {
|
||||||
|
int instanceId = Integer.parseInt(instanceIdStr);
|
||||||
|
nic.setInstanceID(instanceId);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
s_logger.warn("Encountered element of type \"InstanceID\", that could not be parse to an integer number: " + instanceIdStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
nic.setResourceSubType(resourceSubType);
|
||||||
|
nic.setResourceType(resourceType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkForOnlyOneSystemNode(Document doc) throws InternalErrorException {
|
||||||
|
// get hardware VirtualSystem, for now we support only one of those
|
||||||
|
NodeList systemElements = doc.getElementsByTagName("VirtualSystem");
|
||||||
|
if (systemElements.getLength() != 1) {
|
||||||
|
String msg = "found " + systemElements.getLength() + " system definitions in OVA, can only handle exactly one.";
|
||||||
|
s_logger.warn(msg);
|
||||||
|
throw new InternalErrorException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, NetworkPrerequisiteTO> getNetworksFromDocumentTree(Document doc) {
|
||||||
|
NodeList networkElements = doc.getElementsByTagName("Network");
|
||||||
|
Map<String, NetworkPrerequisiteTO> nets = new HashMap<>();
|
||||||
|
for (int i = 0; i < networkElements.getLength(); i++) {
|
||||||
|
|
||||||
|
Element networkElement = (Element)networkElements.item(i);
|
||||||
|
String networkName = getNodeAttribute(networkElement,"ovf","name");
|
||||||
|
|
||||||
|
String description = getChildNodeValue(networkElement, "Description");
|
||||||
|
|
||||||
|
NetworkPrerequisiteTO network = new NetworkPrerequisiteTO();
|
||||||
|
network.setName(networkName);
|
||||||
|
network.setNetworkDescription(description);
|
||||||
|
|
||||||
|
nets.put(networkName,network);
|
||||||
|
}
|
||||||
|
if (s_logger.isTraceEnabled()) {
|
||||||
|
s_logger.trace(String.format("found %d networks in template", nets.size()));
|
||||||
|
}
|
||||||
|
return nets;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hardwareItemContainsConfiguration(OVFVirtualHardwareItemTO item, String configurationId) {
|
||||||
|
if (StringUtils.isBlank(configurationId) || StringUtils.isBlank(item.getConfigurationIds())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String configurationIds = item.getConfigurationIds();
|
||||||
|
if (StringUtils.isNotBlank(configurationIds)) {
|
||||||
|
String[] configurations = configurationIds.split(" ");
|
||||||
|
List<String> confList = Arrays.asList(configurations);
|
||||||
|
return confList.contains(configurationId);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the virtual hardware section and its deployment options as configurations
|
||||||
|
*/
|
||||||
|
public OVFVirtualHardwareSectionTO getVirtualHardwareSectionFromDocument(Document doc) {
|
||||||
|
List<OVFConfigurationTO> configurations = getDeploymentOptionsFromDocumentTree(doc);
|
||||||
|
List<OVFVirtualHardwareItemTO> items = getVirtualHardwareItemsFromDocumentTree(doc);
|
||||||
|
if (CollectionUtils.isNotEmpty(configurations)) {
|
||||||
|
for (OVFConfigurationTO configuration : configurations) {
|
||||||
|
List<OVFVirtualHardwareItemTO> confItems = items.stream().
|
||||||
|
filter(x -> StringUtils.isNotBlank(x.getConfigurationIds())
|
||||||
|
&& hardwareItemContainsConfiguration(x, configuration.getId()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
configuration.setHardwareItems(confItems);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<OVFVirtualHardwareItemTO> commonItems = null;
|
||||||
|
if (CollectionUtils.isNotEmpty(items)) {
|
||||||
|
commonItems = items.stream().filter(x -> StringUtils.isBlank(x.getConfigurationIds())).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
return new OVFVirtualHardwareSectionTO(configurations, commonItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<OVFConfigurationTO> getDeploymentOptionsFromDocumentTree(Document doc) {
|
||||||
|
List<OVFConfigurationTO> options = new ArrayList<>();
|
||||||
|
if (doc == null) {
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
NodeList deploymentOptionSection = doc.getElementsByTagName("DeploymentOptionSection");
|
||||||
|
if (deploymentOptionSection.getLength() == 0) {
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
Node hardwareSectionNode = deploymentOptionSection.item(0);
|
||||||
|
NodeList childNodes = hardwareSectionNode.getChildNodes();
|
||||||
|
int index = 0;
|
||||||
|
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||||
|
Node node = childNodes.item(i);
|
||||||
|
if (node != null && node.getNodeName().equals("Configuration")) {
|
||||||
|
Element configuration = (Element) node;
|
||||||
|
String configurationId = getNodeAttribute(configuration,"ovf","id");
|
||||||
|
String description = getChildNodeValue(configuration, "Description");
|
||||||
|
String label = getChildNodeValue(configuration, "Label");
|
||||||
|
OVFConfigurationTO option = new OVFConfigurationTO(configurationId, label, description, index);
|
||||||
|
options.add(option);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<OVFVirtualHardwareItemTO> getVirtualHardwareItemsFromDocumentTree(Document doc) {
|
||||||
|
List<OVFVirtualHardwareItemTO> items = new LinkedList<>();
|
||||||
|
if (doc == null) {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
NodeList hardwareSection = doc.getElementsByTagName("VirtualHardwareSection");
|
||||||
|
if (hardwareSection.getLength() == 0) {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
Node hardwareSectionNode = hardwareSection.item(0);
|
||||||
|
NodeList childNodes = hardwareSectionNode.getChildNodes();
|
||||||
|
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||||
|
Node node = childNodes.item(i);
|
||||||
|
if (node != null && node.getNodeName().equals("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");
|
||||||
|
OVFVirtualHardwareItemTO item = new OVFVirtualHardwareItemTO();
|
||||||
|
item.setConfigurationIds(configurationIds);
|
||||||
|
item.setAllocationUnits(allocationUnits);
|
||||||
|
item.setDescription(description);
|
||||||
|
item.setElementName(elementName);
|
||||||
|
item.setInstanceId(instanceID);
|
||||||
|
item.setLimit(getLongValueFromString(limit));
|
||||||
|
item.setReservation(getLongValueFromString(reservation));
|
||||||
|
Integer resType = getIntValueFromString(resourceType);
|
||||||
|
if (resType != null) {
|
||||||
|
item.setResourceType(OVFVirtualHardwareItemTO.getResourceTypeFromId(resType));
|
||||||
|
}
|
||||||
|
item.setVirtualQuantity(getLongValueFromString(virtualQuantity));
|
||||||
|
item.setHostResource(hostResource);
|
||||||
|
item.setAddressOnParent(addressOnParent);
|
||||||
|
item.setParent(parent);
|
||||||
|
items.add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long getLongValueFromString(String value) {
|
||||||
|
if (StringUtils.isNotBlank(value)) {
|
||||||
|
try {
|
||||||
|
return Long.parseLong(value);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
s_logger.debug("Could not parse the value: " + value + ", ignoring it");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer getIntValueFromString(String value) {
|
||||||
|
if (StringUtils.isNotBlank(value)) {
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(value);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
s_logger.debug("Could not parse the value: " + value + ", ignoring it");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected byte[] compressOVFEula(String license) throws IOException {
|
||||||
|
CompressionUtil compressionUtil = new CompressionUtil();
|
||||||
|
return compressionUtil.compressString(license);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<OVFEulaSectionTO> getEulaSectionsFromDocument(Document doc) {
|
||||||
|
List<OVFEulaSectionTO> eulas = new LinkedList<>();
|
||||||
|
if (doc == null) {
|
||||||
|
return eulas;
|
||||||
|
}
|
||||||
|
NodeList eulaSections = doc.getElementsByTagName("EulaSection");
|
||||||
|
int eulaIndex = 0;
|
||||||
|
if (eulaSections.getLength() > 0) {
|
||||||
|
for (int index = 0; index < eulaSections.getLength(); index++) {
|
||||||
|
Node eulaNode = eulaSections.item(index);
|
||||||
|
NodeList eulaChildNodes = eulaNode.getChildNodes();
|
||||||
|
String eulaInfo = null;
|
||||||
|
String eulaLicense = null;
|
||||||
|
for (int i = 0; i < eulaChildNodes.getLength(); i++) {
|
||||||
|
Node eulaItem = eulaChildNodes.item(i);
|
||||||
|
if (eulaItem.getNodeName().equalsIgnoreCase("Info")) {
|
||||||
|
eulaInfo = eulaItem.getTextContent();
|
||||||
|
} else if (eulaItem.getNodeName().equalsIgnoreCase("License")) {
|
||||||
|
eulaLicense = eulaItem.getTextContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
byte[] compressedLicense = new byte[0];
|
||||||
|
try {
|
||||||
|
compressedLicense = compressOVFEula(eulaLicense);
|
||||||
|
} catch (IOException e) {
|
||||||
|
s_logger.error("Could not compress the license for info " + eulaInfo);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
OVFEulaSectionTO eula = new OVFEulaSectionTO(eulaInfo, compressedLicense, eulaIndex);
|
||||||
|
eulas.add(eula);
|
||||||
|
eulaIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return eulas;
|
||||||
|
}
|
||||||
|
|
||||||
class OVFFile {
|
class OVFFile {
|
||||||
// <File ovf:href="i-2-8-VM-disk2.vmdk" ovf:id="file1" ovf:size="69120" />
|
// <File ovf:href="i-2-8-VM-disk2.vmdk" ovf:id="file1" ovf:size="69120" />
|
||||||
public String _href;
|
public String _href;
|
||||||
@ -417,7 +877,6 @@ public class OVFHelper {
|
|||||||
//<Disk ovf:capacity="50" ovf:capacityAllocationUnits="byte * 2^20" ovf:diskId="vmdisk2" ovf:fileRef="file2"
|
//<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" />
|
//ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" ovf:populatedSize="43319296" />
|
||||||
public Long _capacity;
|
public Long _capacity;
|
||||||
public String _capacityUnit;
|
|
||||||
public String _diskId;
|
public String _diskId;
|
||||||
public String _fileRef;
|
public String _fileRef;
|
||||||
public Long _populatedSize;
|
public Long _populatedSize;
|
||||||
|
|||||||
@ -30,7 +30,7 @@ import com.cloud.agent.api.LogLevel;
|
|||||||
* Choose "Remote HTTP and SSH Client Routes" to route only traffic destined for the management client(s), when they are on remote networks.</Description>
|
* Choose "Remote HTTP and SSH Client Routes" to route only traffic destined for the management client(s), when they are on remote networks.</Description>
|
||||||
* </Property>
|
* </Property>
|
||||||
*/
|
*/
|
||||||
public class OVFPropertyTO implements OVFProperty {
|
public class OVFPropertyTO {
|
||||||
|
|
||||||
private String key;
|
private String key;
|
||||||
private String type;
|
private String type;
|
||||||
@ -41,18 +41,14 @@ public class OVFPropertyTO implements OVFProperty {
|
|||||||
private String label;
|
private String label;
|
||||||
private String description;
|
private String description;
|
||||||
private Boolean password;
|
private Boolean password;
|
||||||
|
private int index;
|
||||||
|
private String category;
|
||||||
|
|
||||||
public OVFPropertyTO() {
|
public OVFPropertyTO() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public OVFPropertyTO(String key, String value, boolean password) {
|
|
||||||
this.key = key;
|
|
||||||
this.value = value;
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OVFPropertyTO(String key, String type, String value, String qualifiers, boolean userConfigurable,
|
public OVFPropertyTO(String key, String type, String value, String qualifiers, boolean userConfigurable,
|
||||||
String label, String description, boolean password) {
|
String label, String description, boolean password, int index, String category) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
@ -61,9 +57,10 @@ public class OVFPropertyTO implements OVFProperty {
|
|||||||
this.label = label;
|
this.label = label;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
|
this.index = index;
|
||||||
|
this.category = category;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Long getTemplateId() {
|
public Long getTemplateId() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -131,4 +128,12 @@ public class OVFPropertyTO implements OVFProperty {
|
|||||||
public void setPassword(Boolean password) {
|
public void setPassword(Boolean password) {
|
||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getCategory() {
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,365 @@
|
|||||||
|
// 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;
|
||||||
|
|
||||||
|
// From: https://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData.xsd
|
||||||
|
public class OVFVirtualHardwareItemTO {
|
||||||
|
|
||||||
|
//From: https://schemas.dmtf.org/wbem/cim-html/2/CIM_ResourceAllocationSettingData.html
|
||||||
|
public enum HardwareResourceType {
|
||||||
|
Other("Other", 1),
|
||||||
|
ComputerSystem ("Computer System", 2),
|
||||||
|
Processor("Processor", 3),
|
||||||
|
Memory("Memory", 4),
|
||||||
|
IDEController("IDE Controller", 5),
|
||||||
|
ParallelSCSIHBA("Parallel SCSI HBA", 6),
|
||||||
|
FC_HBA("FC HBA", 7),
|
||||||
|
iSCSI_HBA("iSCSI HBA", 8),
|
||||||
|
IB_HCA("IB HCA", 9),
|
||||||
|
EthernetAdapter("Ethernet Adaptor", 10),
|
||||||
|
OtherNetworkAdapter("Other Network Adaptor", 11),
|
||||||
|
IO_Slot("I/O Slot", 12),
|
||||||
|
IO_Device("I/O Device", 13),
|
||||||
|
FloppyDrive("Floppy Drive", 14),
|
||||||
|
CD_Drive("CD Drive", 15),
|
||||||
|
DVD_Drive("DVD Drive", 16),
|
||||||
|
DiskDrive("Disk Drive", 17),
|
||||||
|
TapeDrive("Tape Drive", 18),
|
||||||
|
StorageExtent("Storage Extent", 19),
|
||||||
|
OtherStorageDevice("Other Storage Device", 20),
|
||||||
|
SerialPort("Serial Port", 21),
|
||||||
|
ParallelPort("Parallel Port", 22),
|
||||||
|
USBController("USB Controller", 23),
|
||||||
|
GraphicsController("Graphics Controller", 24),
|
||||||
|
IEEE_1394_Controller("IEEE 1394 Controller", 25),
|
||||||
|
PartitionableUnit("Partitionable Unit", 26),
|
||||||
|
BasePartitionableUnit("base Partitionable Unit", 27),
|
||||||
|
PowerSupply("Power", 28),
|
||||||
|
CoolingCapacity("Cooling Capacity", 29),
|
||||||
|
EthernetSwitchPort("Ethernet Switch Port", 30),
|
||||||
|
LogicalDisk("Logical Disk", 31),
|
||||||
|
StorageVolume("Storage Volume", 32),
|
||||||
|
EthernetConnection("Ethernet Connection", 33),
|
||||||
|
DMTF_reserved("DMTF Reserved", 35),
|
||||||
|
VendorReserved("Vendor Reserved", 32768);
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private int id;
|
||||||
|
|
||||||
|
HardwareResourceType(String name, int id) {
|
||||||
|
this.name = name;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HardwareResourceType getResourceTypeFromId(int id) {
|
||||||
|
if (id <= 33) {
|
||||||
|
for (HardwareResourceType type : HardwareResourceType.values()) {
|
||||||
|
if (type.id == id) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (id <= 32767) {
|
||||||
|
return HardwareResourceType.DMTF_reserved;
|
||||||
|
}
|
||||||
|
return HardwareResourceType.VendorReserved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CustomerVisibility {
|
||||||
|
Unknown, PassedThrough, Virtualized, NotRepresented, DMTFReserved, VendorReserved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum MappingBehavior {
|
||||||
|
Unknown, NotSupported, Dedicated, SoftAffinity, HardAffinity, DMTFReserved, VendorReserved;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String address;
|
||||||
|
private String addressOnParent;
|
||||||
|
private String allocationUnits;
|
||||||
|
private boolean automaticAllocation;
|
||||||
|
private boolean automaticDeallocation;
|
||||||
|
private String caption;
|
||||||
|
private String changeableType;
|
||||||
|
private String componentSetting;
|
||||||
|
private String configurationName;
|
||||||
|
private String connection;
|
||||||
|
private CustomerVisibility customerVisibility;
|
||||||
|
private String description;
|
||||||
|
private String elementName;
|
||||||
|
private Long generation;
|
||||||
|
private String hostResource;
|
||||||
|
private String instanceId;
|
||||||
|
private Long limit;
|
||||||
|
private MappingBehavior mappingBehavior;
|
||||||
|
private String otherResourceType;
|
||||||
|
private String parent;
|
||||||
|
private String poolId;
|
||||||
|
private Long reservation;
|
||||||
|
private String resourceSubtype;
|
||||||
|
private HardwareResourceType resourceType;
|
||||||
|
private String soId;
|
||||||
|
private String soOrgId;
|
||||||
|
private Long virtualQuantity;
|
||||||
|
private String virtualQuantityUnits;
|
||||||
|
private int weight;
|
||||||
|
|
||||||
|
private String configurationIds;
|
||||||
|
|
||||||
|
public String getConfigurationIds() {
|
||||||
|
return configurationIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConfigurationIds(String configurationIds) {
|
||||||
|
this.configurationIds = configurationIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddress(String address) {
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAddressOnParent() {
|
||||||
|
return addressOnParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddressOnParent(String addressOnParent) {
|
||||||
|
this.addressOnParent = addressOnParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAllocationUnits() {
|
||||||
|
return allocationUnits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAllocationUnits(String allocationUnits) {
|
||||||
|
this.allocationUnits = allocationUnits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAutomaticAllocation() {
|
||||||
|
return automaticAllocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutomaticAllocation(boolean automaticAllocation) {
|
||||||
|
this.automaticAllocation = automaticAllocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAutomaticDeallocation() {
|
||||||
|
return automaticDeallocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutomaticDeallocation(boolean automaticDeallocation) {
|
||||||
|
this.automaticDeallocation = automaticDeallocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCaption() {
|
||||||
|
return caption;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCaption(String caption) {
|
||||||
|
this.caption = caption;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getChangeableType() {
|
||||||
|
return changeableType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChangeableType(String changeableType) {
|
||||||
|
this.changeableType = changeableType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getComponentSetting() {
|
||||||
|
return componentSetting;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setComponentSetting(String componentSetting) {
|
||||||
|
this.componentSetting = componentSetting;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getConfigurationName() {
|
||||||
|
return configurationName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConfigurationName(String configurationName) {
|
||||||
|
this.configurationName = configurationName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getConnection() {
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConnection(String connection) {
|
||||||
|
this.connection = connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CustomerVisibility getCustomerVisibility() {
|
||||||
|
return customerVisibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomerVisibility(CustomerVisibility customerVisibility) {
|
||||||
|
this.customerVisibility = customerVisibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getElementName() {
|
||||||
|
return elementName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setElementName(String elementName) {
|
||||||
|
this.elementName = elementName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getGeneration() {
|
||||||
|
return generation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGeneration(Long generation) {
|
||||||
|
this.generation = generation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHostResource() {
|
||||||
|
return hostResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHostResource(String hostResource) {
|
||||||
|
this.hostResource = hostResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInstanceId() {
|
||||||
|
return instanceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInstanceId(String instanceId) {
|
||||||
|
this.instanceId = instanceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getLimit() {
|
||||||
|
return limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLimit(Long limit) {
|
||||||
|
this.limit = limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MappingBehavior getMappingBehavior() {
|
||||||
|
return mappingBehavior;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMappingBehavior(MappingBehavior mappingBehavior) {
|
||||||
|
this.mappingBehavior = mappingBehavior;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOtherResourceType() {
|
||||||
|
return otherResourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOtherResourceType(String otherResourceType) {
|
||||||
|
this.otherResourceType = otherResourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParent(String parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPoolId() {
|
||||||
|
return poolId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPoolId(String poolId) {
|
||||||
|
this.poolId = poolId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getReservation() {
|
||||||
|
return reservation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReservation(Long reservation) {
|
||||||
|
this.reservation = reservation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResourceSubtype() {
|
||||||
|
return resourceSubtype;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResourceSubtype(String resourceSubtype) {
|
||||||
|
this.resourceSubtype = resourceSubtype;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HardwareResourceType getResourceType() {
|
||||||
|
return resourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResourceType(HardwareResourceType resourceType) {
|
||||||
|
this.resourceType = resourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSoId() {
|
||||||
|
return soId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSoId(String soId) {
|
||||||
|
this.soId = soId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSoOrgId() {
|
||||||
|
return soOrgId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSoOrgId(String soOrgId) {
|
||||||
|
this.soOrgId = soOrgId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getVirtualQuantity() {
|
||||||
|
return virtualQuantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVirtualQuantity(Long virtualQuantity) {
|
||||||
|
this.virtualQuantity = virtualQuantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVirtualQuantityUnits() {
|
||||||
|
return virtualQuantityUnits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVirtualQuantityUnits(String virtualQuantityUnits) {
|
||||||
|
this.virtualQuantityUnits = virtualQuantityUnits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWeight() {
|
||||||
|
return weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWeight(int weight) {
|
||||||
|
this.weight = weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
//
|
||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
// or more contributor license agreements. See the NOTICE file
|
// or more contributor license agreements. See the NOTICE file
|
||||||
// distributed with this work for additional information
|
// distributed with this work for additional information
|
||||||
@ -14,18 +15,29 @@
|
|||||||
// KIND, either express or implied. See the License for the
|
// KIND, either express or implied. See the License for the
|
||||||
// specific language governing permissions and limitations
|
// specific language governing permissions and limitations
|
||||||
// under the License.
|
// under the License.
|
||||||
|
//
|
||||||
package com.cloud.storage.dao;
|
package com.cloud.agent.api.storage;
|
||||||
|
|
||||||
import com.cloud.storage.TemplateOVFPropertyVO;
|
|
||||||
import com.cloud.utils.db.GenericDao;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface TemplateOVFPropertiesDao extends GenericDao<TemplateOVFPropertyVO, Long> {
|
public class OVFVirtualHardwareSectionTO {
|
||||||
|
|
||||||
boolean existsOption(long templateId, String key);
|
public OVFVirtualHardwareSectionTO() {
|
||||||
TemplateOVFPropertyVO findByTemplateAndKey(long templateId, String key);
|
}
|
||||||
void saveOptions(List<TemplateOVFPropertyVO> opts);
|
|
||||||
List<TemplateOVFPropertyVO> listByTemplateId(long templateId);
|
private List<OVFConfigurationTO> configurations;
|
||||||
|
private List<OVFVirtualHardwareItemTO> commonHardwareItems;
|
||||||
|
|
||||||
|
public OVFVirtualHardwareSectionTO(List<OVFConfigurationTO> configurations, List<OVFVirtualHardwareItemTO> commonHardwareItems) {
|
||||||
|
this.configurations = configurations;
|
||||||
|
this.commonHardwareItems = commonHardwareItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<OVFConfigurationTO> getConfigurations() {
|
||||||
|
return configurations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<OVFVirtualHardwareItemTO> getCommonHardwareItems() {
|
||||||
|
return commonHardwareItems;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -27,18 +27,14 @@ public class DatadiskTO {
|
|||||||
private boolean isIso;
|
private boolean isIso;
|
||||||
private String diskController;
|
private String diskController;
|
||||||
private String diskControllerSubType;
|
private String diskControllerSubType;
|
||||||
|
private int diskNumber;
|
||||||
|
private String configuration;
|
||||||
|
|
||||||
public DatadiskTO() {
|
public DatadiskTO() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public DatadiskTO(String path, long virtualSize, long fileSize, boolean bootable) {
|
public DatadiskTO(String path, long virtualSize, long fileSize, String diskId, boolean isIso, boolean bootable,
|
||||||
this.path = path;
|
String controller, String controllerSubType, int diskNumber, String configuration) {
|
||||||
this.virtualSize = virtualSize;
|
|
||||||
this.fileSize = fileSize;
|
|
||||||
this.bootable = bootable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DatadiskTO(String path, long virtualSize, long fileSize, String diskId, boolean isIso, boolean bootable, String controller, String controllerSubType) {
|
|
||||||
this.path = path;
|
this.path = path;
|
||||||
this.virtualSize = virtualSize;
|
this.virtualSize = virtualSize;
|
||||||
this.fileSize = fileSize;
|
this.fileSize = fileSize;
|
||||||
@ -47,6 +43,8 @@ public class DatadiskTO {
|
|||||||
this.isIso = isIso;
|
this.isIso = isIso;
|
||||||
this.diskController = controller;
|
this.diskController = controller;
|
||||||
this.diskControllerSubType = controllerSubType;
|
this.diskControllerSubType = controllerSubType;
|
||||||
|
this.diskNumber = diskNumber;
|
||||||
|
this.configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPath() {
|
public String getPath() {
|
||||||
@ -105,4 +103,11 @@ public class DatadiskTO {
|
|||||||
this.diskControllerSubType = diskControllerSubType;
|
this.diskControllerSubType = diskControllerSubType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getDiskNumber() {
|
||||||
|
return this.diskNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getConfiguration() {
|
||||||
|
return configuration;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
// 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.to;
|
||||||
|
|
||||||
|
public class DeployAsIsInfoTO {
|
||||||
|
|
||||||
|
private boolean deployAsIs;
|
||||||
|
private String templatePath;
|
||||||
|
private String deploymentConfiguration;
|
||||||
|
|
||||||
|
public DeployAsIsInfoTO() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDeployAsIs() {
|
||||||
|
return deployAsIs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeployAsIs(boolean deployAsIs) {
|
||||||
|
this.deployAsIs = deployAsIs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTemplatePath() {
|
||||||
|
return templatePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTemplatePath(String templateInSecondaryPath) {
|
||||||
|
this.templatePath = templateInSecondaryPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeploymentConfiguration() {
|
||||||
|
return deploymentConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeploymentConfiguration(String deploymentConfiguration) {
|
||||||
|
this.deploymentConfiguration = deploymentConfiguration;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -23,7 +23,6 @@ import java.util.HashMap;
|
|||||||
import com.cloud.agent.api.LogLevel;
|
import com.cloud.agent.api.LogLevel;
|
||||||
import com.cloud.agent.api.storage.OVFPropertyTO;
|
import com.cloud.agent.api.storage.OVFPropertyTO;
|
||||||
import com.cloud.template.VirtualMachineTemplate.BootloaderType;
|
import com.cloud.template.VirtualMachineTemplate.BootloaderType;
|
||||||
import com.cloud.utils.Pair;
|
|
||||||
import com.cloud.vm.VirtualMachine;
|
import com.cloud.vm.VirtualMachine;
|
||||||
import com.cloud.vm.VirtualMachine.Type;
|
import com.cloud.vm.VirtualMachine.Type;
|
||||||
|
|
||||||
@ -82,7 +81,8 @@ public class VirtualMachineTO {
|
|||||||
Map<String, String> guestOsDetails = new HashMap<String, String>();
|
Map<String, String> guestOsDetails = new HashMap<String, String>();
|
||||||
Map<String, String> extraConfig = new HashMap<>();
|
Map<String, String> extraConfig = new HashMap<>();
|
||||||
@LogLevel(LogLevel.Log4jLevel.Off)
|
@LogLevel(LogLevel.Log4jLevel.Off)
|
||||||
Pair<String, List<OVFPropertyTO>> ovfProperties;
|
List<OVFPropertyTO> ovfProperties;
|
||||||
|
DeployAsIsInfoTO deployAsIsInfo;
|
||||||
|
|
||||||
public VirtualMachineTO(long id, String instanceName, VirtualMachine.Type type, int cpus, Integer speed, long minRam, long maxRam, BootloaderType bootloader,
|
public VirtualMachineTO(long id, String instanceName, VirtualMachine.Type type, int cpus, Integer speed, long minRam, long maxRam, BootloaderType bootloader,
|
||||||
String os, boolean enableHA, boolean limitCpuUse, String vncPassword) {
|
String os, boolean enableHA, boolean limitCpuUse, String vncPassword) {
|
||||||
@ -376,11 +376,11 @@ public class VirtualMachineTO {
|
|||||||
return extraConfig;
|
return extraConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pair<String, List<OVFPropertyTO>> getOvfProperties() {
|
public List<OVFPropertyTO> getOvfProperties() {
|
||||||
return ovfProperties;
|
return ovfProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOvfProperties(Pair<String, List<OVFPropertyTO>> ovfProperties) {
|
public void setOvfProperties(List<OVFPropertyTO> ovfProperties) {
|
||||||
this.ovfProperties = ovfProperties;
|
this.ovfProperties = ovfProperties;
|
||||||
}
|
}
|
||||||
public String getBootType() {
|
public String getBootType() {
|
||||||
@ -402,4 +402,12 @@ public class VirtualMachineTO {
|
|||||||
public void setEnterHardwareSetup(boolean enterHardwareSetup) {
|
public void setEnterHardwareSetup(boolean enterHardwareSetup) {
|
||||||
this.enterHardwareSetup = enterHardwareSetup;
|
this.enterHardwareSetup = enterHardwareSetup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DeployAsIsInfoTO getDeployAsIsInfo() {
|
||||||
|
return deployAsIsInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeployAsIsInfo(DeployAsIsInfoTO deployAsIsInfo) {
|
||||||
|
this.deployAsIsInfo = deployAsIsInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,13 @@ import org.apache.cloudstack.api.InternalIdentity;
|
|||||||
|
|
||||||
public interface ImageStore extends Identity, InternalIdentity {
|
public interface ImageStore extends Identity, InternalIdentity {
|
||||||
|
|
||||||
|
String ACS_PROPERTY_PREFIX = "ACS-property-";
|
||||||
|
String REQUIRED_NETWORK_PREFIX = "ACS-network-";
|
||||||
|
String DISK_DEFINITION_PREFIX = "ACS-disk-";
|
||||||
|
String OVF_HARDWARE_CONFIGURATION_PREFIX = "ACS-configuration-";
|
||||||
|
String OVF_HARDWARE_ITEM_PREFIX = "ACS-hardware-item-";
|
||||||
|
String OVF_EULA_SECTION_PREFIX = "ACS-eula-";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return name of the object store.
|
* @return name of the object store.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -138,4 +138,6 @@ public interface VirtualMachineTemplate extends ControlledEntity, Identity, Inte
|
|||||||
void incrUpdatedCount();
|
void incrUpdatedCount();
|
||||||
|
|
||||||
Date getUpdated();
|
Date getUpdated();
|
||||||
|
|
||||||
|
boolean isDeployAsIs();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,6 +52,8 @@ public class NicProfile implements InternalIdentity, Serializable {
|
|||||||
Integer networkRate;
|
Integer networkRate;
|
||||||
boolean isSecurityGroupEnabled;
|
boolean isSecurityGroupEnabled;
|
||||||
|
|
||||||
|
Integer orderIndex;
|
||||||
|
|
||||||
// IPv4
|
// IPv4
|
||||||
String iPv4Address;
|
String iPv4Address;
|
||||||
String iPv4Netmask;
|
String iPv4Netmask;
|
||||||
@ -381,6 +383,14 @@ public class NicProfile implements InternalIdentity, Serializable {
|
|||||||
this.requestedIPv6 = requestedIPv6;
|
this.requestedIPv6 = requestedIPv6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getOrderIndex() {
|
||||||
|
return orderIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrderIndex(Integer orderIndex) {
|
||||||
|
this.orderIndex = orderIndex;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// OTHER METHODS
|
// OTHER METHODS
|
||||||
//
|
//
|
||||||
@ -410,6 +420,8 @@ public class NicProfile implements InternalIdentity, Serializable {
|
|||||||
broadcastUri = null;
|
broadcastUri = null;
|
||||||
isolationUri = null;
|
isolationUri = null;
|
||||||
|
|
||||||
|
orderIndex = null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -63,4 +63,6 @@ public interface VmDetailConstants {
|
|||||||
String IP6_ADDRESS = "ip6Address";
|
String IP6_ADDRESS = "ip6Address";
|
||||||
String DISK = "disk";
|
String DISK = "disk";
|
||||||
String DISK_OFFERING = "diskOffering";
|
String DISK_OFFERING = "diskOffering";
|
||||||
|
|
||||||
|
String DEPLOY_AS_IS_CONFIGURATION = "configurationId";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -185,6 +185,7 @@ public class ApiConstants {
|
|||||||
public static final String ICMP_TYPE = "icmptype";
|
public static final String ICMP_TYPE = "icmptype";
|
||||||
public static final String ID = "id";
|
public static final String ID = "id";
|
||||||
public static final String IDS = "ids";
|
public static final String IDS = "ids";
|
||||||
|
public static final String INDEX = "index";
|
||||||
public static final String PREVIOUS_ACL_RULE_ID = "previousaclruleid";
|
public static final String PREVIOUS_ACL_RULE_ID = "previousaclruleid";
|
||||||
public static final String NEXT_ACL_RULE_ID = "nextaclruleid";
|
public static final String NEXT_ACL_RULE_ID = "nextaclruleid";
|
||||||
public static final String MOVE_ACL_CONSISTENCY_HASH = "aclconsistencyhash";
|
public static final String MOVE_ACL_CONSISTENCY_HASH = "aclconsistencyhash";
|
||||||
@ -262,7 +263,7 @@ public class ApiConstants {
|
|||||||
public static final String OUTOFBANDMANAGEMENT_POWERSTATE = "outofbandmanagementpowerstate";
|
public static final String OUTOFBANDMANAGEMENT_POWERSTATE = "outofbandmanagementpowerstate";
|
||||||
public static final String OUTOFBANDMANAGEMENT_ENABLED = "outofbandmanagementenabled";
|
public static final String OUTOFBANDMANAGEMENT_ENABLED = "outofbandmanagementenabled";
|
||||||
public static final String OUTPUT = "output";
|
public static final String OUTPUT = "output";
|
||||||
public static final String OVF_PROPERTIES = "ovfproperties";
|
public static final String PROPERTIES = "properties";
|
||||||
public static final String PARAMS = "params";
|
public static final String PARAMS = "params";
|
||||||
public static final String PARENT_ID = "parentid";
|
public static final String PARENT_ID = "parentid";
|
||||||
public static final String PARENT_DOMAIN_ID = "parentdomainid";
|
public static final String PARENT_DOMAIN_ID = "parentdomainid";
|
||||||
@ -824,6 +825,10 @@ public class ApiConstants {
|
|||||||
public static final String BOOT_TYPE = "boottype";
|
public static final String BOOT_TYPE = "boottype";
|
||||||
public static final String BOOT_MODE = "bootmode";
|
public static final String BOOT_MODE = "bootmode";
|
||||||
public static final String BOOT_INTO_SETUP = "bootintosetup";
|
public static final String BOOT_INTO_SETUP = "bootintosetup";
|
||||||
|
public static final String DEPLOY_AS_IS = "deployasis";
|
||||||
|
public static final String CROSS_ZONES = "crossZones";
|
||||||
|
public static final String TEMPLATETYPE = "templatetype";
|
||||||
|
public static final String SOURCETEMPLATEID = "sourcetemplateid";
|
||||||
|
|
||||||
public enum BootType {
|
public enum BootType {
|
||||||
UEFI, BIOS;
|
UEFI, BIOS;
|
||||||
|
|||||||
@ -204,6 +204,9 @@ public class ImportUnmanagedInstanceCmd extends BaseAsyncCmd {
|
|||||||
for (Map<String, String> entry : (Collection<Map<String, String>>)nicNetworkList.values()) {
|
for (Map<String, String> entry : (Collection<Map<String, String>>)nicNetworkList.values()) {
|
||||||
String nic = entry.get(VmDetailConstants.NIC);
|
String nic = entry.get(VmDetailConstants.NIC);
|
||||||
String networkUuid = entry.get(VmDetailConstants.NETWORK);
|
String networkUuid = entry.get(VmDetailConstants.NETWORK);
|
||||||
|
if (LOGGER.isTraceEnabled()) {
|
||||||
|
LOGGER.trace(String.format("nic, '%s', goes on net, '%s'", nic, networkUuid));
|
||||||
|
}
|
||||||
if (Strings.isNullOrEmpty(nic) || Strings.isNullOrEmpty(networkUuid) || _entityMgr.findByUuid(Network.class, networkUuid) == null) {
|
if (Strings.isNullOrEmpty(nic) || Strings.isNullOrEmpty(networkUuid) || _entityMgr.findByUuid(Network.class, networkUuid) == null) {
|
||||||
throw new InvalidParameterValueException(String.format("Network ID: %s for NIC ID: %s is invalid", networkUuid, nic));
|
throw new InvalidParameterValueException(String.format("Network ID: %s for NIC ID: %s is invalid", networkUuid, nic));
|
||||||
}
|
}
|
||||||
@ -219,11 +222,14 @@ public class ImportUnmanagedInstanceCmd extends BaseAsyncCmd {
|
|||||||
for (Map<String, String> entry : (Collection<Map<String, String>>)nicIpAddressList.values()) {
|
for (Map<String, String> entry : (Collection<Map<String, String>>)nicIpAddressList.values()) {
|
||||||
String nic = entry.get(VmDetailConstants.NIC);
|
String nic = entry.get(VmDetailConstants.NIC);
|
||||||
String ipAddress = Strings.emptyToNull(entry.get(VmDetailConstants.IP4_ADDRESS));
|
String ipAddress = Strings.emptyToNull(entry.get(VmDetailConstants.IP4_ADDRESS));
|
||||||
|
if (LOGGER.isTraceEnabled()) {
|
||||||
|
LOGGER.trace(String.format("nic, '%s', gets ip, '%s'", nic, ipAddress));
|
||||||
|
}
|
||||||
if (Strings.isNullOrEmpty(nic)) {
|
if (Strings.isNullOrEmpty(nic)) {
|
||||||
throw new InvalidParameterValueException(String.format("NIC ID: '%s' is invalid for IP address mapping", nic));
|
throw new InvalidParameterValueException(String.format("NIC ID: '%s' is invalid for IP address mapping", nic));
|
||||||
}
|
}
|
||||||
if (Strings.isNullOrEmpty(ipAddress)) {
|
if (Strings.isNullOrEmpty(ipAddress)) {
|
||||||
throw new InvalidParameterValueException(String.format("IP address '%s' for NIC ID: %s is invalid", ipAddress, nic));
|
throw new InvalidParameterValueException(String.format("Empty address for NIC ID: %s is invalid", nic));
|
||||||
}
|
}
|
||||||
if (!Strings.isNullOrEmpty(ipAddress) && !ipAddress.equals("auto") && !NetUtils.isValidIp4(ipAddress)) {
|
if (!Strings.isNullOrEmpty(ipAddress) && !ipAddress.equals("auto") && !NetUtils.isValidIp4(ipAddress)) {
|
||||||
throw new InvalidParameterValueException(String.format("IP address '%s' for NIC ID: %s is invalid", ipAddress, nic));
|
throw new InvalidParameterValueException(String.format("IP address '%s' for NIC ID: %s is invalid", ipAddress, nic));
|
||||||
@ -239,12 +245,15 @@ public class ImportUnmanagedInstanceCmd extends BaseAsyncCmd {
|
|||||||
Map<String, Long> dataDiskToDiskOfferingMap = new HashMap<>();
|
Map<String, Long> dataDiskToDiskOfferingMap = new HashMap<>();
|
||||||
if (MapUtils.isNotEmpty(dataDiskToDiskOfferingList)) {
|
if (MapUtils.isNotEmpty(dataDiskToDiskOfferingList)) {
|
||||||
for (Map<String, String> entry : (Collection<Map<String, String>>)dataDiskToDiskOfferingList.values()) {
|
for (Map<String, String> entry : (Collection<Map<String, String>>)dataDiskToDiskOfferingList.values()) {
|
||||||
String nic = entry.get(VmDetailConstants.DISK);
|
String disk = entry.get(VmDetailConstants.DISK);
|
||||||
String offeringUuid = entry.get(VmDetailConstants.DISK_OFFERING);
|
String offeringUuid = entry.get(VmDetailConstants.DISK_OFFERING);
|
||||||
if (Strings.isNullOrEmpty(nic) || Strings.isNullOrEmpty(offeringUuid) || _entityMgr.findByUuid(DiskOffering.class, offeringUuid) == null) {
|
if (LOGGER.isTraceEnabled()) {
|
||||||
throw new InvalidParameterValueException(String.format("Disk offering ID: %s for disk ID: %s is invalid", offeringUuid, nic));
|
LOGGER.trace(String.format("disk, '%s', gets offering, '%s'", disk, offeringUuid));
|
||||||
}
|
}
|
||||||
dataDiskToDiskOfferingMap.put(nic, _entityMgr.findByUuid(DiskOffering.class, offeringUuid).getId());
|
if (Strings.isNullOrEmpty(disk) || Strings.isNullOrEmpty(offeringUuid) || _entityMgr.findByUuid(DiskOffering.class, offeringUuid) == null) {
|
||||||
|
throw new InvalidParameterValueException(String.format("Disk offering ID: %s for disk ID: %s is invalid", offeringUuid, disk));
|
||||||
|
}
|
||||||
|
dataDiskToDiskOfferingMap.put(disk, _entityMgr.findByUuid(DiskOffering.class, offeringUuid).getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dataDiskToDiskOfferingMap;
|
return dataDiskToDiskOfferingMap;
|
||||||
|
|||||||
@ -65,6 +65,24 @@ public class ListServiceOfferingsCmd extends BaseListDomainResourcesCmd {
|
|||||||
since = "4.13")
|
since = "4.13")
|
||||||
private Long zoneId;
|
private Long zoneId;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.CPU_NUMBER,
|
||||||
|
type = CommandType.INTEGER,
|
||||||
|
description = "the CPU number that listed offerings must support",
|
||||||
|
since = "4.15")
|
||||||
|
private Integer cpuNumber;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.MEMORY,
|
||||||
|
type = CommandType.INTEGER,
|
||||||
|
description = "the RAM memory that listed offering must support",
|
||||||
|
since = "4.15")
|
||||||
|
private Integer memory;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.CPU_SPEED,
|
||||||
|
type = CommandType.INTEGER,
|
||||||
|
description = "the CPU speed that listed offerings must support",
|
||||||
|
since = "4.15")
|
||||||
|
private Integer cpuSpeed;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -93,6 +111,18 @@ public class ListServiceOfferingsCmd extends BaseListDomainResourcesCmd {
|
|||||||
return zoneId;
|
return zoneId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getCpuNumber() {
|
||||||
|
return cpuNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMemory() {
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getCpuSpeed() {
|
||||||
|
return cpuSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|||||||
@ -1,68 +0,0 @@
|
|||||||
// 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 org.apache.cloudstack.api.command.user.template;
|
|
||||||
|
|
||||||
import com.cloud.exception.ConcurrentOperationException;
|
|
||||||
import com.cloud.exception.InsufficientCapacityException;
|
|
||||||
import com.cloud.exception.NetworkRuleConflictException;
|
|
||||||
import com.cloud.exception.ResourceAllocationException;
|
|
||||||
import com.cloud.exception.ResourceUnavailableException;
|
|
||||||
import org.apache.cloudstack.acl.RoleType;
|
|
||||||
import org.apache.cloudstack.api.APICommand;
|
|
||||||
import org.apache.cloudstack.api.ApiConstants;
|
|
||||||
import org.apache.cloudstack.api.BaseCmd;
|
|
||||||
import org.apache.cloudstack.api.BaseListCmd;
|
|
||||||
import org.apache.cloudstack.api.Parameter;
|
|
||||||
import org.apache.cloudstack.api.ServerApiException;
|
|
||||||
import org.apache.cloudstack.api.response.ListResponse;
|
|
||||||
import org.apache.cloudstack.api.response.TemplateOVFPropertyResponse;
|
|
||||||
import org.apache.cloudstack.api.response.TemplateResponse;
|
|
||||||
import org.apache.cloudstack.context.CallContext;
|
|
||||||
|
|
||||||
@APICommand(name = ListTemplateOVFProperties.APINAME,
|
|
||||||
description = "List template OVF properties if available.",
|
|
||||||
responseObject = TemplateOVFPropertyResponse.class,
|
|
||||||
authorized = {RoleType.Admin, RoleType.DomainAdmin, RoleType.ResourceAdmin, RoleType.User})
|
|
||||||
public class ListTemplateOVFProperties extends BaseListCmd {
|
|
||||||
|
|
||||||
public static final String APINAME = "listTemplateOvfProperties";
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = TemplateResponse.class,
|
|
||||||
description = "the template ID", required = true)
|
|
||||||
private Long templateId;
|
|
||||||
|
|
||||||
public Long getTemplateId() {
|
|
||||||
return templateId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
|
|
||||||
ListResponse<TemplateOVFPropertyResponse> response = _queryService.listTemplateOVFProperties(this);
|
|
||||||
response.setResponseName(getCommandName());
|
|
||||||
setResponseObject(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getCommandName() {
|
|
||||||
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getEntityOwnerId() {
|
|
||||||
return CallContext.current().getCallingAccount().getId();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -16,8 +16,12 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package org.apache.cloudstack.api.command.user.template;
|
package org.apache.cloudstack.api.command.user.template;
|
||||||
|
|
||||||
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.apache.cloudstack.api.APICommand;
|
import org.apache.cloudstack.api.APICommand;
|
||||||
import org.apache.cloudstack.api.ApiCommandJobType;
|
import org.apache.cloudstack.api.ApiCommandJobType;
|
||||||
@ -82,10 +86,35 @@ public class ListTemplatesCmd extends BaseListTaggedResourcesCmd implements User
|
|||||||
@Parameter(name = ApiConstants.PARENT_TEMPLATE_ID, type = CommandType.UUID, entityType = TemplateResponse.class, description = "list datadisk templates by parent template id", since = "4.4")
|
@Parameter(name = ApiConstants.PARENT_TEMPLATE_ID, type = CommandType.UUID, entityType = TemplateResponse.class, description = "list datadisk templates by parent template id", since = "4.4")
|
||||||
private Long parentTemplateId;
|
private Long parentTemplateId;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.DETAILS,
|
||||||
|
type = CommandType.LIST,
|
||||||
|
collectionType = CommandType.STRING,
|
||||||
|
description = "comma separated list of template details requested, value can be a list of [ all, resource, min]")
|
||||||
|
private List<String> viewDetails;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public EnumSet<ApiConstants.DomainDetails> getDetails() throws InvalidParameterValueException {
|
||||||
|
EnumSet<ApiConstants.DomainDetails> dv;
|
||||||
|
if (CollectionUtils.isEmpty(viewDetails)) {
|
||||||
|
dv = EnumSet.of(ApiConstants.DomainDetails.all);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
ArrayList<ApiConstants.DomainDetails> dc = new ArrayList<>();
|
||||||
|
for (String detail : viewDetails) {
|
||||||
|
dc.add(ApiConstants.DomainDetails.valueOf(detail));
|
||||||
|
}
|
||||||
|
dv = EnumSet.copyOf(dc);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new InvalidParameterValueException("The details parameter contains a non permitted value. The allowed values are " +
|
||||||
|
EnumSet.allOf(ApiConstants.DomainDetails.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dv;
|
||||||
|
}
|
||||||
|
|
||||||
public String getHypervisor() {
|
public String getHypervisor() {
|
||||||
return hypervisor;
|
return hypervisor;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -162,6 +162,13 @@ public class RegisterTemplateCmd extends BaseCmd implements UserCmd {
|
|||||||
description = "true if template should bypass Secondary Storage and be downloaded to Primary Storage on deployment")
|
description = "true if template should bypass Secondary Storage and be downloaded to Primary Storage on deployment")
|
||||||
private Boolean directDownload;
|
private Boolean directDownload;
|
||||||
|
|
||||||
|
@Parameter(name= ApiConstants.DEPLOY_AS_IS,
|
||||||
|
type = CommandType.BOOLEAN,
|
||||||
|
description = "VMware only: true if template should not strip and define disks and networks but leave those to the template definition",
|
||||||
|
since = "4.15"
|
||||||
|
)
|
||||||
|
private Boolean deployAsIs;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -274,6 +281,10 @@ public class RegisterTemplateCmd extends BaseCmd implements UserCmd {
|
|||||||
return directDownload == null ? false : directDownload;
|
return directDownload == null ? false : directDownload;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean isDeployAsIs() {
|
||||||
|
return deployAsIs == null ? false : deployAsIs;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|||||||
@ -52,6 +52,7 @@ import org.apache.cloudstack.api.response.TemplateResponse;
|
|||||||
import org.apache.cloudstack.api.response.UserVmResponse;
|
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||||
import org.apache.cloudstack.api.response.ZoneResponse;
|
import org.apache.cloudstack.api.response.ZoneResponse;
|
||||||
import org.apache.cloudstack.context.CallContext;
|
import org.apache.cloudstack.context.CallContext;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.collections.MapUtils;
|
import org.apache.commons.collections.MapUtils;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
@ -72,6 +73,8 @@ import com.cloud.uservm.UserVm;
|
|||||||
import com.cloud.utils.net.Dhcp;
|
import com.cloud.utils.net.Dhcp;
|
||||||
import com.cloud.utils.net.NetUtils;
|
import com.cloud.utils.net.NetUtils;
|
||||||
import com.cloud.vm.VirtualMachine;
|
import com.cloud.vm.VirtualMachine;
|
||||||
|
import com.cloud.vm.VmDetailConstants;
|
||||||
|
import com.google.common.base.Strings;
|
||||||
|
|
||||||
@APICommand(name = "deployVirtualMachine", description = "Creates and automatically starts a virtual machine based on a service offering, disk offering, and template.", responseObject = UserVmResponse.class, responseView = ResponseView.Restricted, entityType = {VirtualMachine.class},
|
@APICommand(name = "deployVirtualMachine", description = "Creates and automatically starts a virtual machine based on a service offering, disk offering, and template.", responseObject = UserVmResponse.class, responseView = ResponseView.Restricted, entityType = {VirtualMachine.class},
|
||||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = true)
|
requestHasSensitiveInfo = false, responseHasSensitiveInfo = true)
|
||||||
@ -221,10 +224,16 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
|
|||||||
@Parameter(name = ApiConstants.COPY_IMAGE_TAGS, type = CommandType.BOOLEAN, since = "4.13", description = "if true the image tags (if any) will be copied to the VM, default value is false")
|
@Parameter(name = ApiConstants.COPY_IMAGE_TAGS, type = CommandType.BOOLEAN, since = "4.13", description = "if true the image tags (if any) will be copied to the VM, default value is false")
|
||||||
private Boolean copyImageTags;
|
private Boolean copyImageTags;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.OVF_PROPERTIES, type = CommandType.MAP, since = "4.13",
|
@Parameter(name = ApiConstants.PROPERTIES, type = CommandType.MAP, since = "4.15",
|
||||||
description = "used to specify the OVF properties.")
|
description = "used to specify the vApp properties.")
|
||||||
@LogLevel(LogLevel.Log4jLevel.Off)
|
@LogLevel(LogLevel.Log4jLevel.Off)
|
||||||
private Map vmOvfProperties;
|
private Map vAppProperties;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.NIC_NETWORK_LIST, type = CommandType.MAP, since = "4.15",
|
||||||
|
description = "VMware only: used to specify network mapping of a vApp VMware template registered \"as-is\"." +
|
||||||
|
" Example nicnetworklist[0].ip=Nic-101&nicnetworklist[0].network=uuid")
|
||||||
|
@LogLevel(LogLevel.Log4jLevel.Off)
|
||||||
|
private Map vAppNetworks;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
@ -311,11 +320,10 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getVmProperties() {
|
||||||
public Map<String, String> getVmOVFProperties() {
|
|
||||||
Map<String, String> map = new HashMap<>();
|
Map<String, String> map = new HashMap<>();
|
||||||
if (MapUtils.isNotEmpty(vmOvfProperties)) {
|
if (MapUtils.isNotEmpty(vAppProperties)) {
|
||||||
Collection parameterCollection = vmOvfProperties.values();
|
Collection parameterCollection = vAppProperties.values();
|
||||||
Iterator iterator = parameterCollection.iterator();
|
Iterator iterator = parameterCollection.iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
HashMap<String, String> entry = (HashMap<String, String>)iterator.next();
|
HashMap<String, String> entry = (HashMap<String, String>)iterator.next();
|
||||||
@ -325,6 +333,32 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<Integer, Long> getVmNetworkMap() {
|
||||||
|
Map<Integer, Long> map = new HashMap<>();
|
||||||
|
if (MapUtils.isNotEmpty(vAppNetworks)) {
|
||||||
|
Collection parameterCollection = vAppNetworks.values();
|
||||||
|
Iterator iterator = parameterCollection.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
HashMap<String, String> entry = (HashMap<String, String>) iterator.next();
|
||||||
|
Integer nic;
|
||||||
|
try {
|
||||||
|
nic = Integer.valueOf(entry.get(VmDetailConstants.NIC));
|
||||||
|
} catch (NumberFormatException nfe) {
|
||||||
|
nic = null;
|
||||||
|
}
|
||||||
|
String networkUuid = entry.get(VmDetailConstants.NETWORK);
|
||||||
|
if (s_logger.isTraceEnabled()) {
|
||||||
|
s_logger.trace(String.format("nic, '%s', goes on net, '%s'", nic, networkUuid));
|
||||||
|
}
|
||||||
|
if (nic == null || Strings.isNullOrEmpty(networkUuid) || _entityMgr.findByUuid(Network.class, networkUuid) == null) {
|
||||||
|
throw new InvalidParameterValueException(String.format("Network ID: %s for NIC ID: %s is invalid", networkUuid, nic));
|
||||||
|
}
|
||||||
|
map.put(nic, _entityMgr.findByUuid(Network.class, networkUuid).getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
public String getGroup() {
|
public String getGroup() {
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
@ -374,6 +408,13 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<Long> getNetworkIds() {
|
public List<Long> getNetworkIds() {
|
||||||
|
if (MapUtils.isNotEmpty(vAppNetworks)) {
|
||||||
|
if (CollectionUtils.isNotEmpty(networkIds) || ipAddress != null || getIp6Address() != null || MapUtils.isNotEmpty(ipToNetworkList)) {
|
||||||
|
throw new InvalidParameterValueException(String.format("%s can't be specified along with %s, %s, %s", ApiConstants.NIC_NETWORK_LIST, ApiConstants.NETWORK_IDS, ApiConstants.IP_ADDRESS, ApiConstants.IP_NETWORK_LIST));
|
||||||
|
} else {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (ipToNetworkList != null && !ipToNetworkList.isEmpty()) {
|
if (ipToNetworkList != null && !ipToNetworkList.isEmpty()) {
|
||||||
if ((networkIds != null && !networkIds.isEmpty()) || ipAddress != null || getIp6Address() != null) {
|
if ((networkIds != null && !networkIds.isEmpty()) || ipAddress != null || getIp6Address() != null) {
|
||||||
throw new InvalidParameterValueException("ipToNetworkMap can't be specified along with networkIds or ipAddress");
|
throw new InvalidParameterValueException("ipToNetworkMap can't be specified along with networkIds or ipAddress");
|
||||||
|
|||||||
@ -0,0 +1,124 @@
|
|||||||
|
// 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 org.apache.cloudstack.api.net;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* container for the network prerequisites as found in the appliance template
|
||||||
|
*
|
||||||
|
* for OVA:
|
||||||
|
* {code}
|
||||||
|
* <Network ovf:name="Management0-0">
|
||||||
|
* <Description>Management Network Interface</Description>
|
||||||
|
* </Network>
|
||||||
|
* {code}
|
||||||
|
* {code}
|
||||||
|
* <Item>
|
||||||
|
* <rasd:AddressOnParent>7</rasd:AddressOnParent>
|
||||||
|
* <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
|
||||||
|
* <rasd:Connection>Management0-0</rasd:Connection>
|
||||||
|
* <rasd:Description>E1000 Ethernet adapter on "Management Network"</rasd:Description>
|
||||||
|
* <rasd:ElementName>Network adapter 1</rasd:ElementName>
|
||||||
|
* <rasd:InstanceID>6</rasd:InstanceID>
|
||||||
|
* <rasd:ResourceSubType>E1000</rasd:ResourceSubType>
|
||||||
|
* <rasd:ResourceType>10</rasd:ResourceType>
|
||||||
|
* </Item>
|
||||||
|
* {code}
|
||||||
|
*/
|
||||||
|
public class NetworkPrerequisiteTO {
|
||||||
|
String name;
|
||||||
|
String networkDescription;
|
||||||
|
|
||||||
|
int addressOnParent;
|
||||||
|
boolean automaticAllocation;
|
||||||
|
String nicDescription;
|
||||||
|
String elementName;
|
||||||
|
int InstanceID;
|
||||||
|
String resourceSubType;
|
||||||
|
String resourceType;
|
||||||
|
|
||||||
|
public int getAddressOnParent() {
|
||||||
|
return addressOnParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddressOnParent(int addressOnParent) {
|
||||||
|
this.addressOnParent = addressOnParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAutomaticAllocation() {
|
||||||
|
return automaticAllocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutomaticAllocation(boolean automaticAllocation) {
|
||||||
|
this.automaticAllocation = automaticAllocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNicDescription() {
|
||||||
|
return nicDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNicDescription(String nicDescription) {
|
||||||
|
this.nicDescription = nicDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getElementName() {
|
||||||
|
return elementName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setElementName(String elementName) {
|
||||||
|
this.elementName = elementName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getInstanceID() {
|
||||||
|
return InstanceID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInstanceID(int instanceID) {
|
||||||
|
InstanceID = instanceID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResourceSubType() {
|
||||||
|
return resourceSubType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResourceSubType(String resourceSubType) {
|
||||||
|
this.resourceSubType = resourceSubType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResourceType() {
|
||||||
|
return resourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResourceType(String resourceType) {
|
||||||
|
this.resourceType = resourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNetworkDescription() {
|
||||||
|
return networkDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNetworkDescription(String networkDescription) {
|
||||||
|
this.networkDescription = networkDescription;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -16,14 +16,14 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package org.apache.cloudstack.api.response;
|
package org.apache.cloudstack.api.response;
|
||||||
|
|
||||||
import com.cloud.agent.api.storage.OVFProperty;
|
|
||||||
import com.cloud.serializer.Param;
|
import com.cloud.serializer.Param;
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
import org.apache.cloudstack.api.ApiConstants;
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
import org.apache.cloudstack.api.BaseResponse;
|
import org.apache.cloudstack.api.BaseResponse;
|
||||||
import org.apache.cloudstack.api.EntityReference;
|
|
||||||
|
|
||||||
@EntityReference(value = OVFProperty.class)
|
/**
|
||||||
|
* the placeholder of parameters to fill for deployment
|
||||||
|
*/
|
||||||
public class TemplateOVFPropertyResponse extends BaseResponse {
|
public class TemplateOVFPropertyResponse extends BaseResponse {
|
||||||
|
|
||||||
@SerializedName(ApiConstants.KEY)
|
@SerializedName(ApiConstants.KEY)
|
||||||
@ -58,6 +58,27 @@ public class TemplateOVFPropertyResponse extends BaseResponse {
|
|||||||
@Param(description = "the ovf property label")
|
@Param(description = "the ovf property label")
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.INDEX)
|
||||||
|
@Param(description = "the ovf property index")
|
||||||
|
private Integer index;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.CATEGORY)
|
||||||
|
@Param(description = "the ovf property category")
|
||||||
|
private String category;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
if (!(other instanceof TemplateOVFPropertyResponse)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return key != null && key.equals(((TemplateOVFPropertyResponse)other).key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return key.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
public String getKey() {
|
public String getKey() {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
@ -121,4 +142,20 @@ public class TemplateOVFPropertyResponse extends BaseResponse {
|
|||||||
public void setPassword(Boolean password) {
|
public void setPassword(Boolean password) {
|
||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndex(Integer index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCategory() {
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCategory(String category) {
|
||||||
|
this.category = category;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
package org.apache.cloudstack.api.response;
|
package org.apache.cloudstack.api.response;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -55,7 +56,7 @@ public class TemplateResponse extends BaseResponseWithTagInformation implements
|
|||||||
@Param(description = "the date this template was created")
|
@Param(description = "the date this template was created")
|
||||||
private Date created;
|
private Date created;
|
||||||
|
|
||||||
@SerializedName("removed")
|
@SerializedName(ApiConstants.REMOVED)
|
||||||
@Param(description = "the date this template was removed")
|
@Param(description = "the date this template was removed")
|
||||||
private Date removed;
|
private Date removed;
|
||||||
|
|
||||||
@ -80,7 +81,7 @@ public class TemplateResponse extends BaseResponseWithTagInformation implements
|
|||||||
@Param(description = "true if this template is a featured template, false otherwise")
|
@Param(description = "true if this template is a featured template, false otherwise")
|
||||||
private boolean featured;
|
private boolean featured;
|
||||||
|
|
||||||
@SerializedName("crossZones")
|
@SerializedName(ApiConstants.CROSS_ZONES)
|
||||||
@Param(description = "true if the template is managed across all Zones, false otherwise")
|
@Param(description = "true if the template is managed across all Zones, false otherwise")
|
||||||
private boolean crossZones;
|
private boolean crossZones;
|
||||||
|
|
||||||
@ -122,7 +123,7 @@ public class TemplateResponse extends BaseResponseWithTagInformation implements
|
|||||||
@Param(description = "the physical size of the template")
|
@Param(description = "the physical size of the template")
|
||||||
private Long physicalSize;
|
private Long physicalSize;
|
||||||
|
|
||||||
@SerializedName("templatetype")
|
@SerializedName(ApiConstants.TEMPLATETYPE)
|
||||||
@Param(description = "the type of the template")
|
@Param(description = "the type of the template")
|
||||||
private String templateType;
|
private String templateType;
|
||||||
|
|
||||||
@ -146,7 +147,7 @@ public class TemplateResponse extends BaseResponseWithTagInformation implements
|
|||||||
@Param(description = "checksum of the template")
|
@Param(description = "checksum of the template")
|
||||||
private String checksum;
|
private String checksum;
|
||||||
|
|
||||||
@SerializedName("sourcetemplateid")
|
@SerializedName(ApiConstants.SOURCETEMPLATEID)
|
||||||
@Param(description = "the template ID of the parent template if present")
|
@Param(description = "the template ID of the parent template if present")
|
||||||
private String sourcetemplateId;
|
private String sourcetemplateId;
|
||||||
|
|
||||||
@ -154,7 +155,7 @@ public class TemplateResponse extends BaseResponseWithTagInformation implements
|
|||||||
@Param(description = "the ID of the secondary storage host for the template")
|
@Param(description = "the ID of the secondary storage host for the template")
|
||||||
private String hostId;
|
private String hostId;
|
||||||
|
|
||||||
@SerializedName("hostname")
|
@SerializedName(ApiConstants.HOST_NAME)
|
||||||
@Param(description = "the name of the secondary storage host for the template")
|
@Param(description = "the name of the secondary storage host for the template")
|
||||||
private String hostName;
|
private String hostName;
|
||||||
|
|
||||||
@ -172,7 +173,7 @@ public class TemplateResponse extends BaseResponseWithTagInformation implements
|
|||||||
|
|
||||||
@SerializedName(ApiConstants.DETAILS)
|
@SerializedName(ApiConstants.DETAILS)
|
||||||
@Param(description = "additional key/value details tied with template")
|
@Param(description = "additional key/value details tied with template")
|
||||||
private Map details;
|
private Map<String, String> details;
|
||||||
|
|
||||||
@SerializedName(ApiConstants.DOWNLOAD_DETAILS)
|
@SerializedName(ApiConstants.DOWNLOAD_DETAILS)
|
||||||
@Param(description = "Lists the download progress of a template across all secondary storages")
|
@Param(description = "Lists the download progress of a template across all secondary storages")
|
||||||
@ -194,12 +195,18 @@ public class TemplateResponse extends BaseResponseWithTagInformation implements
|
|||||||
@Param(description = "KVM Only: true if template is directly downloaded to Primary Storage bypassing Secondary Storage")
|
@Param(description = "KVM Only: true if template is directly downloaded to Primary Storage bypassing Secondary Storage")
|
||||||
private Boolean directDownload;
|
private Boolean directDownload;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.DEPLOY_AS_IS)
|
||||||
|
@Param(description = "VMware only: true if template is deployed without orchestrating disks and networks but \"as-is\" defined in the template.")
|
||||||
|
private Boolean deployAsIs;
|
||||||
|
|
||||||
@SerializedName("parenttemplateid")
|
@SerializedName("parenttemplateid")
|
||||||
@Param(description = "if Datadisk template, then id of the root disk template this template belongs to")
|
@Param(description = "if Datadisk template, then id of the root disk template this template belongs to")
|
||||||
|
@Deprecated(since = "4.15")
|
||||||
private String parentTemplateId;
|
private String parentTemplateId;
|
||||||
|
|
||||||
@SerializedName("childtemplates")
|
@SerializedName("childtemplates")
|
||||||
@Param(description = "if root disk template, then ids of the datas disk templates this template owns")
|
@Param(description = "if root disk template, then ids of the datas disk templates this template owns")
|
||||||
|
@Deprecated(since = "4.15")
|
||||||
private Set<ChildTemplateResponse> childTemplates;
|
private Set<ChildTemplateResponse> childTemplates;
|
||||||
|
|
||||||
@SerializedName(ApiConstants.REQUIRES_HVM)
|
@SerializedName(ApiConstants.REQUIRES_HVM)
|
||||||
@ -360,14 +367,21 @@ public class TemplateResponse extends BaseResponseWithTagInformation implements
|
|||||||
this.projectName = projectName;
|
this.projectName = projectName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map getDetails() {
|
public Map<String, String> getDetails() {
|
||||||
return this.details;
|
return this.details;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDetails(Map details) {
|
public void setDetails(Map<String, String> details) {
|
||||||
this.details = details;
|
this.details = details;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addDetail(String key, String value) {
|
||||||
|
if (this.details == null) {
|
||||||
|
setDetails(new HashMap<>());
|
||||||
|
}
|
||||||
|
this.details.put(key,value);
|
||||||
|
}
|
||||||
|
|
||||||
public void setTags(Set<ResourceTagResponse> tags) {
|
public void setTags(Set<ResourceTagResponse> tags) {
|
||||||
this.tags = tags;
|
this.tags = tags;
|
||||||
}
|
}
|
||||||
@ -396,6 +410,10 @@ public class TemplateResponse extends BaseResponseWithTagInformation implements
|
|||||||
return directDownload;
|
return directDownload;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDeployAsIs(Boolean deployAsIs) {
|
||||||
|
this.deployAsIs = deployAsIs;
|
||||||
|
}
|
||||||
|
|
||||||
public void setParentTemplateId(String parentTemplateId) {
|
public void setParentTemplateId(String parentTemplateId) {
|
||||||
this.parentTemplateId = parentTemplateId;
|
this.parentTemplateId = parentTemplateId;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,7 +44,6 @@ import org.apache.cloudstack.api.command.user.project.ListProjectsCmd;
|
|||||||
import org.apache.cloudstack.api.command.user.resource.ListDetailOptionsCmd;
|
import org.apache.cloudstack.api.command.user.resource.ListDetailOptionsCmd;
|
||||||
import org.apache.cloudstack.api.command.user.securitygroup.ListSecurityGroupsCmd;
|
import org.apache.cloudstack.api.command.user.securitygroup.ListSecurityGroupsCmd;
|
||||||
import org.apache.cloudstack.api.command.user.tag.ListTagsCmd;
|
import org.apache.cloudstack.api.command.user.tag.ListTagsCmd;
|
||||||
import org.apache.cloudstack.api.command.user.template.ListTemplateOVFProperties;
|
|
||||||
import org.apache.cloudstack.api.command.user.template.ListTemplatesCmd;
|
import org.apache.cloudstack.api.command.user.template.ListTemplatesCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vm.ListVMsCmd;
|
import org.apache.cloudstack.api.command.user.vm.ListVMsCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd;
|
import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd;
|
||||||
@ -74,7 +73,6 @@ import org.apache.cloudstack.api.response.SecurityGroupResponse;
|
|||||||
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
|
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
|
||||||
import org.apache.cloudstack.api.response.StoragePoolResponse;
|
import org.apache.cloudstack.api.response.StoragePoolResponse;
|
||||||
import org.apache.cloudstack.api.response.StorageTagResponse;
|
import org.apache.cloudstack.api.response.StorageTagResponse;
|
||||||
import org.apache.cloudstack.api.response.TemplateOVFPropertyResponse;
|
|
||||||
import org.apache.cloudstack.api.response.TemplateResponse;
|
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||||
import org.apache.cloudstack.api.response.UserResponse;
|
import org.apache.cloudstack.api.response.UserResponse;
|
||||||
import org.apache.cloudstack.api.response.UserVmResponse;
|
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||||
@ -173,7 +171,5 @@ public interface QueryService {
|
|||||||
|
|
||||||
ListResponse<ManagementServerResponse> listManagementServers(ListMgmtsCmd cmd);
|
ListResponse<ManagementServerResponse> listManagementServers(ListMgmtsCmd cmd);
|
||||||
|
|
||||||
ListResponse<TemplateOVFPropertyResponse> listTemplateOVFProperties(ListTemplateOVFProperties cmd);
|
|
||||||
|
|
||||||
List<RouterHealthCheckResultResponse> listRouterHealthChecks(GetRouterHealthCheckResultsCmd cmd);
|
List<RouterHealthCheckResultResponse> listRouterHealthChecks(GetRouterHealthCheckResultsCmd cmd);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,16 +40,689 @@ public class OVFHelperTest {
|
|||||||
"</Property>" +
|
"</Property>" +
|
||||||
"</ProductSection>";
|
"</ProductSection>";
|
||||||
|
|
||||||
|
private String ovfFileDeploymentOptionsSection =
|
||||||
|
"<DeploymentOptionSection>\n" +
|
||||||
|
" <Info>Deployment Configuration information</Info>\n" +
|
||||||
|
" <Configuration ovf:id=\"ASAv5\">\n" +
|
||||||
|
" <Label>100 Mbps (ASAv5)</Label>\n" +
|
||||||
|
" <Description>Use this option to deploy an ASAv with a maximum throughput of 100 Mbps (uses 1 vCPU and 2 GB of memory).</Description>\n" +
|
||||||
|
" </Configuration>\n" +
|
||||||
|
" <Configuration ovf:id=\"ASAv10\">\n" +
|
||||||
|
" <Label>1 Gbps (ASAv10)</Label>\n" +
|
||||||
|
" <Description>Use this option to deploy an ASAv with a maximum throughput of 1 Gbps (uses 1 vCPU and 2 GB of memory).</Description>\n" +
|
||||||
|
" </Configuration>\n" +
|
||||||
|
" <Configuration ovf:id=\"ASAv30\">\n" +
|
||||||
|
" <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>";
|
||||||
|
|
||||||
|
private String ovfFileVirtualHardwareSection =
|
||||||
|
"<VirtualHardwareSection ovf:transport=\"iso\">\n" +
|
||||||
|
" <Info>Virtual hardware requirements</Info>\n" +
|
||||||
|
" <System>\n" +
|
||||||
|
" <vssd:ElementName>Virtual Hardware Family</vssd:ElementName>\n" +
|
||||||
|
" <vssd:InstanceID>0</vssd:InstanceID>\n" +
|
||||||
|
" <vssd:VirtualSystemIdentifier>ASAv</vssd:VirtualSystemIdentifier>\n" +
|
||||||
|
" <vssd:VirtualSystemType>vmx-08,vmx-09</vssd:VirtualSystemType>\n" +
|
||||||
|
" </System>\n" +
|
||||||
|
" <Item ovf:configuration=\"ASAv5 ASAv10\">\n" +
|
||||||
|
" <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>\n" +
|
||||||
|
" <rasd:Description>Number of Virtual CPUs</rasd:Description>\n" +
|
||||||
|
" <rasd:ElementName>1 virtual CPU(s)</rasd:ElementName>\n" +
|
||||||
|
" <rasd:InstanceID>1</rasd:InstanceID>\n" +
|
||||||
|
" <rasd:Limit>5000</rasd:Limit>\n" +
|
||||||
|
" <rasd:Reservation>1000</rasd:Reservation>\n" +
|
||||||
|
" <rasd:ResourceType>3</rasd:ResourceType>\n" +
|
||||||
|
" <rasd:VirtualQuantity>1</rasd:VirtualQuantity>\n" +
|
||||||
|
" </Item>\n" +
|
||||||
|
" <Item ovf:configuration=\"ASAv30\">\n" +
|
||||||
|
" <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>\n" +
|
||||||
|
" <rasd:Description>Number of Virtual CPUs</rasd:Description>\n" +
|
||||||
|
" <rasd:ElementName>4 virtual CPU(s)</rasd:ElementName>\n" +
|
||||||
|
" <rasd:InstanceID>1</rasd:InstanceID>\n" +
|
||||||
|
" <rasd:Limit>20000</rasd:Limit>\n" +
|
||||||
|
" <rasd:Reservation>1000</rasd:Reservation>\n" +
|
||||||
|
" <rasd:ResourceType>3</rasd:ResourceType>\n" +
|
||||||
|
" <rasd:VirtualQuantity>4</rasd:VirtualQuantity>\n" +
|
||||||
|
" </Item>\n" +
|
||||||
|
" <Item ovf:configuration=\"ASAv5 ASAv10\">\n" +
|
||||||
|
" <rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>\n" +
|
||||||
|
" <rasd:Description>Memory Size</rasd:Description>\n" +
|
||||||
|
" <rasd:ElementName>2048MB of memory</rasd:ElementName>\n" +
|
||||||
|
" <rasd:InstanceID>2</rasd:InstanceID>\n" +
|
||||||
|
" <rasd:Limit>2048</rasd:Limit>\n" +
|
||||||
|
" <rasd:Reservation>2048</rasd:Reservation>\n" +
|
||||||
|
" <rasd:ResourceType>4</rasd:ResourceType>\n" +
|
||||||
|
" <rasd:VirtualQuantity>2048</rasd:VirtualQuantity>\n" +
|
||||||
|
" </Item>\n" +
|
||||||
|
" <Item ovf:configuration=\"ASAv30\">\n" +
|
||||||
|
" <rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>\n" +
|
||||||
|
" <rasd:Description>Memory Size</rasd:Description>\n" +
|
||||||
|
" <rasd:ElementName>8192MB of memory</rasd:ElementName>\n" +
|
||||||
|
" <rasd:InstanceID>2</rasd:InstanceID>\n" +
|
||||||
|
" <rasd:Limit>8192</rasd:Limit>\n" +
|
||||||
|
" <rasd:Reservation>8192</rasd:Reservation>\n" +
|
||||||
|
" <rasd:ResourceType>4</rasd:ResourceType>\n" +
|
||||||
|
" <rasd:VirtualQuantity>8192</rasd:VirtualQuantity>\n" +
|
||||||
|
" </Item>\n" +
|
||||||
|
" <Item>\n" +
|
||||||
|
" <rasd:Address>0</rasd:Address>\n" +
|
||||||
|
" <rasd:Description>SCSI Controller</rasd:Description>\n" +
|
||||||
|
" <rasd:ElementName>SCSI controller 0</rasd:ElementName>\n" +
|
||||||
|
" <rasd:InstanceID>3</rasd:InstanceID>\n" +
|
||||||
|
" <rasd:ResourceSubType>lsilogic</rasd:ResourceSubType>\n" +
|
||||||
|
" <rasd:ResourceType>6</rasd:ResourceType>\n" +
|
||||||
|
" </Item>\n" +
|
||||||
|
" <Item>\n" +
|
||||||
|
" <rasd:Address>0</rasd:Address>\n" +
|
||||||
|
" <rasd:Description>IDE Controller</rasd:Description>\n" +
|
||||||
|
" <rasd:ElementName>IDE 0</rasd:ElementName>\n" +
|
||||||
|
" <rasd:InstanceID>4</rasd:InstanceID>\n" +
|
||||||
|
" <rasd:ResourceType>5</rasd:ResourceType>\n" +
|
||||||
|
" </Item>\n" +
|
||||||
|
" <Item ovf:required=\"false\">\n" +
|
||||||
|
" <rasd:AddressOnParent>0</rasd:AddressOnParent>\n" +
|
||||||
|
" <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>\n" +
|
||||||
|
" <rasd:ElementName>CD/DVD Drive</rasd:ElementName>\n" +
|
||||||
|
" <rasd:InstanceID>5</rasd:InstanceID>\n" +
|
||||||
|
" <rasd:Parent>4</rasd:Parent>\n" +
|
||||||
|
" <rasd:ResourceType>15</rasd:ResourceType>\n" +
|
||||||
|
" </Item>\n" +
|
||||||
|
" <Item ovf:required=\"false\">\n" +
|
||||||
|
" <rasd:AddressOnParent>1</rasd:AddressOnParent>\n" +
|
||||||
|
" <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>\n" +
|
||||||
|
" <rasd:ElementName>CD/DVD Drive</rasd:ElementName>\n" +
|
||||||
|
" <rasd:HostResource>ovf:/file/file3</rasd:HostResource>\n" +
|
||||||
|
" <rasd:InstanceID>18</rasd:InstanceID>\n" +
|
||||||
|
" <rasd:Parent>4</rasd:Parent>\n" +
|
||||||
|
" <rasd:ResourceType>15</rasd:ResourceType>\n" +
|
||||||
|
" </Item>\n" +
|
||||||
|
" <Item>\n" +
|
||||||
|
" <rasd:AddressOnParent>7</rasd:AddressOnParent>\n" +
|
||||||
|
" <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>\n" +
|
||||||
|
" <rasd:Connection>Management0-0</rasd:Connection>\n" +
|
||||||
|
" <rasd:Description>E1000 Ethernet adapter on \"Management Network\"</rasd:Description>\n" +
|
||||||
|
" <rasd:ElementName>Network adapter 1</rasd:ElementName>\n" +
|
||||||
|
" <rasd:InstanceID>6</rasd:InstanceID>\n" +
|
||||||
|
" <rasd:ResourceSubType>E1000</rasd:ResourceSubType>\n" +
|
||||||
|
" <rasd:ResourceType>10</rasd:ResourceType>\n" +
|
||||||
|
" </Item>\n" +
|
||||||
|
" <Item>\n" +
|
||||||
|
" <rasd:AddressOnParent>0</rasd:AddressOnParent>\n" +
|
||||||
|
" <rasd:ElementName>Hard disk 1</rasd:ElementName>\n" +
|
||||||
|
" <rasd:HostResource>ovf:/disk/vmdisk1</rasd:HostResource>\n" +
|
||||||
|
" <rasd:InstanceID>7</rasd:InstanceID>\n" +
|
||||||
|
" <rasd:Parent>3</rasd:Parent>\n" +
|
||||||
|
" <rasd:ResourceType>17</rasd:ResourceType>\n" +
|
||||||
|
" </Item>\n" +
|
||||||
|
" <Item>\n" +
|
||||||
|
" <rasd:AddressOnParent>1</rasd:AddressOnParent>\n" +
|
||||||
|
" <rasd:ElementName>Hard disk 2</rasd:ElementName>\n" +
|
||||||
|
" <rasd:HostResource>ovf:/disk/vmdisk2</rasd:HostResource>\n" +
|
||||||
|
" <rasd:InstanceID>8</rasd:InstanceID>\n" +
|
||||||
|
" <rasd:Parent>3</rasd:Parent>\n" +
|
||||||
|
" <rasd:ResourceType>17</rasd:ResourceType>\n" +
|
||||||
|
" </Item>\n" +
|
||||||
|
" <Item>\n" +
|
||||||
|
" <rasd:AddressOnParent>8</rasd:AddressOnParent>\n" +
|
||||||
|
" <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>\n" +
|
||||||
|
" <rasd:Connection>GigabitEthernet0-0</rasd:Connection>\n" +
|
||||||
|
" <rasd:Description>General purpose E1000 Ethernet adapter</rasd:Description>\n" +
|
||||||
|
" <rasd:ElementName>Network adapter 2</rasd:ElementName>\n" +
|
||||||
|
" <rasd:InstanceID>9</rasd:InstanceID>\n" +
|
||||||
|
" <rasd:ResourceSubType>E1000</rasd:ResourceSubType>\n" +
|
||||||
|
" <rasd:ResourceType>10</rasd:ResourceType>\n" +
|
||||||
|
" </Item>\n" +
|
||||||
|
" <Item>\n" +
|
||||||
|
" <rasd:AddressOnParent>9</rasd:AddressOnParent>\n" +
|
||||||
|
" <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>\n" +
|
||||||
|
" <rasd:Connection>GigabitEthernet0-1</rasd:Connection>\n" +
|
||||||
|
" <rasd:Description>General purpose E1000 Ethernet adapter</rasd:Description>\n" +
|
||||||
|
" <rasd:ElementName>Network adapter 3</rasd:ElementName>\n" +
|
||||||
|
" <rasd:InstanceID>10</rasd:InstanceID>\n" +
|
||||||
|
" <rasd:ResourceSubType>E1000</rasd:ResourceSubType>\n" +
|
||||||
|
" <rasd:ResourceType>10</rasd:ResourceType>\n" +
|
||||||
|
" </Item>\n" +
|
||||||
|
" <Item>\n" +
|
||||||
|
" <rasd:AddressOnParent>10</rasd:AddressOnParent>\n" +
|
||||||
|
" <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>\n" +
|
||||||
|
" <rasd:Connection>GigabitEthernet0-2</rasd:Connection>\n" +
|
||||||
|
" <rasd:Description>General purpose E1000 Ethernet adapter</rasd:Description>\n" +
|
||||||
|
" <rasd:ElementName>Network adapter 4</rasd:ElementName>\n" +
|
||||||
|
" <rasd:InstanceID>11</rasd:InstanceID>\n" +
|
||||||
|
" <rasd:ResourceSubType>E1000</rasd:ResourceSubType>\n" +
|
||||||
|
" <rasd:ResourceType>10</rasd:ResourceType>\n" +
|
||||||
|
" </Item>\n" +
|
||||||
|
" <Item>\n" +
|
||||||
|
" <rasd:AddressOnParent>11</rasd:AddressOnParent>\n" +
|
||||||
|
" <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>\n" +
|
||||||
|
" <rasd:Connection>GigabitEthernet0-3</rasd:Connection>\n" +
|
||||||
|
" <rasd:Description>General purpose E1000 Ethernet adapter</rasd:Description>\n" +
|
||||||
|
" <rasd:ElementName>Network adapter 5</rasd:ElementName>\n" +
|
||||||
|
" <rasd:InstanceID>12</rasd:InstanceID>\n" +
|
||||||
|
" <rasd:ResourceSubType>E1000</rasd:ResourceSubType>\n" +
|
||||||
|
" <rasd:ResourceType>10</rasd:ResourceType>\n" +
|
||||||
|
" </Item>\n" +
|
||||||
|
" <Item>\n" +
|
||||||
|
" <rasd:AddressOnParent>12</rasd:AddressOnParent>\n" +
|
||||||
|
" <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>\n" +
|
||||||
|
" <rasd:Connection>GigabitEthernet0-4</rasd:Connection>\n" +
|
||||||
|
" <rasd:Description>General purpose E1000 Ethernet adapter</rasd:Description>\n" +
|
||||||
|
" <rasd:ElementName>Network adapter 6</rasd:ElementName>\n" +
|
||||||
|
" <rasd:InstanceID>13</rasd:InstanceID>\n" +
|
||||||
|
" <rasd:ResourceSubType>E1000</rasd:ResourceSubType>\n" +
|
||||||
|
" <rasd:ResourceType>10</rasd:ResourceType>\n" +
|
||||||
|
" </Item>\n" +
|
||||||
|
" <Item>\n" +
|
||||||
|
" <rasd:AddressOnParent>13</rasd:AddressOnParent>\n" +
|
||||||
|
" <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>\n" +
|
||||||
|
" <rasd:Connection>GigabitEthernet0-5</rasd:Connection>\n" +
|
||||||
|
" <rasd:Description>General purpose E1000 Ethernet adapter</rasd:Description>\n" +
|
||||||
|
" <rasd:ElementName>Network adapter 7</rasd:ElementName>\n" +
|
||||||
|
" <rasd:InstanceID>14</rasd:InstanceID>\n" +
|
||||||
|
" <rasd:ResourceSubType>E1000</rasd:ResourceSubType>\n" +
|
||||||
|
" <rasd:ResourceType>10</rasd:ResourceType>\n" +
|
||||||
|
" </Item>\n" +
|
||||||
|
" <Item>\n" +
|
||||||
|
" <rasd:AddressOnParent>14</rasd:AddressOnParent>\n" +
|
||||||
|
" <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>\n" +
|
||||||
|
" <rasd:Connection>GigabitEthernet0-6</rasd:Connection>\n" +
|
||||||
|
" <rasd:Description>General purpose E1000 Ethernet adapter</rasd:Description>\n" +
|
||||||
|
" <rasd:ElementName>Network adapter 8</rasd:ElementName>\n" +
|
||||||
|
" <rasd:InstanceID>15</rasd:InstanceID>\n" +
|
||||||
|
" <rasd:ResourceSubType>E1000</rasd:ResourceSubType>\n" +
|
||||||
|
" <rasd:ResourceType>10</rasd:ResourceType>\n" +
|
||||||
|
" </Item>\n" +
|
||||||
|
" <Item>\n" +
|
||||||
|
" <rasd:AddressOnParent>15</rasd:AddressOnParent>\n" +
|
||||||
|
" <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>\n" +
|
||||||
|
" <rasd:Connection>GigabitEthernet0-7</rasd:Connection>\n" +
|
||||||
|
" <rasd:Description>General purpose E1000 Ethernet adapter</rasd:Description>\n" +
|
||||||
|
" <rasd:ElementName>Network adapter 9</rasd:ElementName>\n" +
|
||||||
|
" <rasd:InstanceID>16</rasd:InstanceID>\n" +
|
||||||
|
" <rasd:ResourceSubType>E1000</rasd:ResourceSubType>\n" +
|
||||||
|
" <rasd:ResourceType>10</rasd:ResourceType>\n" +
|
||||||
|
" </Item>\n" +
|
||||||
|
" <Item>\n" +
|
||||||
|
" <rasd:AddressOnParent>16</rasd:AddressOnParent>\n" +
|
||||||
|
" <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>\n" +
|
||||||
|
" <rasd:Connection>GigabitEthernet0-8</rasd:Connection>\n" +
|
||||||
|
" <rasd:Description>Default HA failover E1000 Ethernet adapter, or additional standalone general purpose adapter</rasd:Description>\n" +
|
||||||
|
" <rasd:ElementName>Network adapter 10</rasd:ElementName>\n" +
|
||||||
|
" <rasd:InstanceID>17</rasd:InstanceID>\n" +
|
||||||
|
" <rasd:ResourceSubType>E1000</rasd:ResourceSubType>\n" +
|
||||||
|
" <rasd:ResourceType>10</rasd:ResourceType>\n" +
|
||||||
|
" </Item>\n" +
|
||||||
|
" <vmw:ExtraConfig vmw:key=\"monitor_control.pseudo_perfctr\" vmw:value=\"TRUE\"></vmw:ExtraConfig>\n" +
|
||||||
|
" </VirtualHardwareSection>";
|
||||||
|
|
||||||
|
private String eulaSections =
|
||||||
|
"<VirtualSystem>\n" +
|
||||||
|
"<EulaSection>\n" +
|
||||||
|
" <Info>end-user license agreement</Info>\n" +
|
||||||
|
" <License>END USER LICENSE AGREEMENT\n" +
|
||||||
|
"\n" +
|
||||||
|
"IMPORTANT: PLEASE READ THIS END USER LICENSE AGREEMENT CAREFULLY. IT IS VERY IMPORTANT THAT YOU CHECK THAT YOU ARE PURCHASING CISCO SOFTWARE OR EQUIPMENT FROM AN APPROVED SOURCE AND THAT YOU, OR THE ENTITY YOU REPRESENT (COLLECTIVELY, THE \"CUSTOMER\") HAVE BEEN REGISTERED AS THE END USER FOR THE PURPOSES OF THIS CISCO END USER LICENSE AGREEMENT. IF YOU ARE NOT REGISTERED AS THE END USER YOU HAVE NO LICENSE TO USE THE SOFTWARE AND THE LIMITED WARRANTY IN THIS END USER LICENSE AGREEMENT DOES NOT APPLY. ASSUMING YOU HAVE PURCHASED FROM AN APPROVED SOURCE, DOWNLOADING, INSTALLING OR USING CISCO OR CISCO-SUPPLIED SOFTWARE CONSTITUTES ACCEPTANCE OF THIS AGREEMENT.\n" +
|
||||||
|
"\n" +
|
||||||
|
"CISCO SYSTEMS, INC. OR ITS AFFILIATE LICENSING THE SOFTWARE (\"CISCO\") IS WILLING TO LICENSE THIS SOFTWARE TO YOU ONLY UPON THE CONDITION THAT YOU PURCHASED THE SOFTWARE FROM AN APPROVED SOURCE AND THAT YOU ACCEPT ALL OF THE TERMS CONTAINED IN THIS END USER LICENSE AGREEMENT PLUS ANY ADDITIONAL LIMITATIONS ON THE LICENSE SET FORTH IN A SUPPLEMENTAL LICENSE AGREEMENT ACCOMPANYING THE PRODUCT, MADE AVAILABLE AT THE TIME OF YOUR ORDER, OR POSTED ON THE CISCO WEBSITE AT www.cisco.com/go/terms (COLLECTIVELY THE \"AGREEMENT\"). TO THE EXTENT OF ANY CONFLICT BETWEEN THE TERMS OF THIS END USER LICENSE AGREEMENT AND ANY SUPPLEMENTAL LICENSE AGREEMENT, THE SUPPLEMENTAL LICENSE AGREEMENT SHALL APPLY. BY DOWNLOADING, INSTALLING, OR USING THE SOFTWARE, YOU ARE REPRESENTING THAT YOU PURCHASED THE SOFTWARE FROM AN APPROVED SOURCE AND BINDING YOURSELF TO THE AGREEMENT. IF YOU DO " +
|
||||||
|
"NOT AGREE TO ALL OF THE TERMS OF THE AGREEMENT, THEN CISCO IS UNWILLING TO LICENSE THE SOFTWARE TO YOU AND (A) YOU MAY NOT DOWNLOAD, INSTALL OR USE THE SOFTWARE, AND (B) YOU MAY RETURN THE SOFTWARE (INCLUDING ANY UNOPENED CD PACKAGE AND ANY WRITTEN MATERIALS) FOR A FULL REFUND, OR, IF THE SOFTWARE AND WRITTEN MATERIALS ARE SUPPLIED AS PART OF ANOTHER PRODUCT, YOU MAY RETURN THE ENTIRE PRODUCT FOR A FULL REFUND. YOUR RIGHT TO RETURN AND REFUND EXPIRES 30 DAYS AFTER PURCHASE FROM AN APPROVED SOURCE, AND APPLIES ONLY IF YOU ARE THE ORIGINAL AND REGISTERED END USER PURCHASER. FOR THE PURPOSES OF THIS END USER LICENSE AGREEMENT, AN \"APPROVED SOURCE\" MEANS (A) CISCO; OR (B) A DISTRIBUTOR OR SYSTEMS INTEGRATOR AUTHORIZED BY CISCO TO DISTRIBUTE / SELL CISCO EQUIPMENT, SOFTWARE AND SERVICES WITHIN YOUR TERRITORY TO END " +
|
||||||
|
"USERS; OR (C) A RESELLER AUTHORIZED BY ANY SUCH DISTRIBUTOR OR SYSTEMS INTEGRATOR IN ACCORDANCE WITH THE TERMS OF THE DISTRIBUTOR'S AGREEMENT WITH CISCO TO DISTRIBUTE / SELL THE CISCO EQUIPMENT, SOFTWARE AND SERVICES WITHIN YOUR TERRITORY TO END USERS.\n" +
|
||||||
|
"\n" +
|
||||||
|
"THE FOLLOWING TERMS OF THE AGREEMENT GOVERN CUSTOMER'S USE OF THE SOFTWARE (DEFINED BELOW), EXCEPT TO THE EXTENT: (A) THERE IS A SEPARATE SIGNED CONTRACT BETWEEN CUSTOMER AND CISCO GOVERNING CUSTOMER'S USE OF THE SOFTWARE, OR (B) THE SOFTWARE INCLUDES A SEPARATE \"CLICK-ACCEPT\" LICENSE AGREEMENT OR THIRD PARTY LICENSE AGREEMENT AS PART OF THE INSTALLATION OR DOWNLOAD PROCESS GOVERNING CUSTOMER'S USE OF THE SOFTWARE. TO THE EXTENT OF A CONFLICT BETWEEN THE PROVISIONS OF THE FOREGOING DOCUMENTS, THE ORDER OF PRECEDENCE SHALL BE (1)THE SIGNED CONTRACT, (2) THE CLICK-ACCEPT AGREEMENT OR THIRD PARTY LICENSE AGREEMENT, AND (3) THE AGREEMENT. FOR PURPOSES OF THE AGREEMENT, \"SOFTWARE\" SHALL MEAN COMPUTER PROGRAMS, INCLUDING FIRMWARE AND COMPUTER PROGRAMS EMBEDDED IN CISCO EQUIPMENT, AS PROVIDED TO CUSTOMER BY AN APPROVED SOURCE, AND ANY UPGRADES, UPDATES, BUG FIXES " +
|
||||||
|
"OR MODIFIED VERSIONS THERETO (COLLECTIVELY, \"UPGRADES\"), ANY OF THE SAME WHICH HAS BEEN RELICENSED UNDER THE CISCO SOFTWARE TRANSFER AND RE-LICENSING POLICY (AS MAY BE AMENDED BY CISCO FROM TIME TO TIME) OR BACKUP COPIES OF ANY OF THE FOREGOING.\n" +
|
||||||
|
"\n" +
|
||||||
|
"License. Conditioned upon compliance with the terms and conditions of the Agreement, Cisco grants to Customer a nonexclusive and nontransferable license to use for Customer's internal business purposes the Software and the Documentation for which Customer has paid the required license fees to an Approved Source. \"Documentation\" means written information (whether contained in user or technical manuals, training materials, specifications or otherwise) pertaining to the Software and made available by an Approved Source with the Software in any manner (including on CD-Rom, or on-line). In order to use the Software, Customer may be required to input a registration number or product authorization key and register Customer's copy of the Software online at Cisco's website to obtain the necessary license key or license file.\n" +
|
||||||
|
"\n" +
|
||||||
|
"Customer's license to use the Software shall be limited to, and Customer shall not use the Software in excess of, a single hardware chassis or card or such other limitations as are set forth in the applicable Supplemental License Agreement or in the applicable purchase order which has been accepted by an Approved Source and for which Customer has paid to an Approved Source the required license fee (the \"Purchase Order\").\n" +
|
||||||
|
"\n" +
|
||||||
|
"Unless otherwise expressly provided in the Documentation or any applicable Supplemental License Agreement, Customer shall use the Software solely as embedded in, for execution on, or (where the applicable Documentation permits installation on non-Cisco equipment) for communication with Cisco equipment owned or leased by Customer and used for Customer's internal business purposes. No other licenses are granted by implication, estoppel or otherwise.\n" +
|
||||||
|
"\n" +
|
||||||
|
"For evaluation or beta copies for which Cisco does not charge a license fee, the above requirement to pay license fees does not apply.\n" +
|
||||||
|
"\n" +
|
||||||
|
"General Limitations. This is a license, not a transfer of title, to the Software and Documentation, and Cisco retains ownership of all copies of the Software and Documentation. Customer acknowledges that the Software and Documentation contain trade secrets of Cisco or its suppliers or licensors, including but not limited to the specific internal design and structure of individual programs and associated interface information. Except as otherwise expressly provided under the Agreement, Customer shall only use the Software in connection with the use of Cisco equipment purchased by the Customer from an Approved Source and Customer shall have no right, and Customer specifically agrees not to:\n" +
|
||||||
|
"\n" +
|
||||||
|
"(i) transfer, assign or sublicense its license rights to any other person or entity (other than in compliance with any Cisco relicensing/transfer policy then in force), or use the Software on Cisco equipment not purchased by the Customer from an Approved Source or on secondhand Cisco equipment, and Customer acknowledges that any attempted transfer, assignment, sublicense or use shall be void;\n" +
|
||||||
|
"\n" +
|
||||||
|
"(ii) make error corrections to or otherwise modify or adapt the Software or create derivative works based upon the Software, or permit third parties to do the same;\n" +
|
||||||
|
"\n" +
|
||||||
|
"(iii) reverse engineer or decompile, decrypt, disassemble or otherwise reduce the Software to human-readable form, except to the extent otherwise expressly permitted under applicable law notwithstanding this restriction or except to the extent that Cisco is legally required to permit such specific activity pursuant to any applicable open source license;\n" +
|
||||||
|
"\n" +
|
||||||
|
"(iv) publish any results of benchmark tests run on the Software;\n" +
|
||||||
|
"\n" +
|
||||||
|
"(v) use or permit the Software to be used to perform services for third parties, whether on a service bureau or time sharing basis or otherwise, without the express written authorization of Cisco; or\n" +
|
||||||
|
"\n" +
|
||||||
|
"(vi) disclose, provide, or otherwise make available trade secrets contained within the Software and Documentation in any form to any third party without the prior written consent of Cisco. Customer shall implement reasonable security measures to protect such trade secrets.\n" +
|
||||||
|
"\n" +
|
||||||
|
"To the extent required by applicable law, and at Customer's written request, Cisco shall provide Customer with the interface information needed to achieve interoperability between the Software and another independently created program, on payment of Cisco's applicable fee, if any. Customer shall observe strict obligations of confidentiality with respect to such information and shall use such information in compliance with any applicable terms and conditions upon which Cisco makes such information available.\n" +
|
||||||
|
"\n" +
|
||||||
|
"Software, Upgrades and Additional Copies. NOTWITHSTANDING ANY OTHER PROVISION OF THE AGREEMENT: (1) CUSTOMER HAS NO LICENSE OR RIGHT TO MAKE OR USE ANY ADDITIONAL COPIES OR UPGRADES UNLESS CUSTOMER, AT THE TIME OF MAKING OR ACQUIRING SUCH COPY OR UPGRADE, ALREADY HOLDS A VALID LICENSE TO THE ORIGINAL SOFTWARE AND HAS PAID THE APPLICABLE FEE TO AN APPROVED SOURCE FOR THE UPGRADE OR ADDITIONAL COPIES; (2) USE OF UPGRADES IS LIMITED TO CISCO EQUIPMENT SUPPLIED BY AN APPROVED SOURCE FOR WHICH CUSTOMER IS THE ORIGINAL END USER PURCHASER OR LESSEE OR OTHERWISE HOLDS A VALID LICENSE TO USE THE SOFTWARE WHICH IS BEING UPGRADED; AND (3) THE MAKING AND USE OF ADDITIONAL COPIES IS LIMITED TO NECESSARY BACKUP PURPOSES ONLY.\n" +
|
||||||
|
"\n" +
|
||||||
|
"Proprietary Notices. Customer agrees to maintain and reproduce all copyright, proprietary, and other notices on all copies, in any form, of the Software in the same form and manner that such copyright and other proprietary notices are included on the Software. Except as expressly authorized in the Agreement, Customer shall not make any copies or duplicates of any Software without the prior written permission of Cisco.\n" +
|
||||||
|
"\n" +
|
||||||
|
"Term and Termination. The Agreement and the license granted herein shall remain effective until terminated. Customer may terminate the Agreement and the license at any time by destroying all copies of Software and any Documentation. Customer's rights under the Agreement will terminate immediately without notice from Cisco if Customer fails to comply with any provision of the Agreement. Upon termination, Customer shall destroy all copies of Software and Documentation in its possession or control. All confidentiality obligations of Customer, all restrictions and limitations imposed on the Customer under the section titled \"General Limitations\" and all limitations of liability and disclaimers and restrictions of warranty shall survive termination of this Agreement. In addition, the provisions of the sections titled \"U.S. Government End User Purchasers\" and \"General Terms Applicable to the Limited Warranty Statement " +
|
||||||
|
"and End User License Agreement\" shall survive termination of the Agreement.\n" +
|
||||||
|
"\n" +
|
||||||
|
"Customer Records. Customer grants to Cisco and its independent accountants the right to examine Customer's books, records and accounts during Customer's normal business hours to verify compliance with this Agreement. In the event such audit discloses non-compliance with this Agreement, Customer shall promptly pay to Cisco the appropriate license fees, plus the reasonable cost of conducting the audit.\n" +
|
||||||
|
"\n" +
|
||||||
|
"Export, Re-Export, Transfer and Use Controls. The Software, Documentation and technology or direct products thereof (hereafter referred to as Software and Technology), supplied by Cisco under the Agreement are subject to export controls under the laws and regulations of the United States (\"U.S.\") and any other applicable countries' laws and regulations. Customer shall comply with such laws and regulations governing export, re-export, import, transfer and use of Cisco Software and Technology and will obtain all required U.S. and local authorizations, permits, or licenses. Cisco and Customer each agree to provide the other information, support documents, and assistance as may reasonably be required by the other in connection with securing authorizations or licenses. Information regarding compliance with export, re-export, transfer and use may be located at the following URL: " +
|
||||||
|
"www.cisco.com/web/about/doing_business/legal/global_export_trade/general_export/contract_compliance.html\n" +
|
||||||
|
"\n" +
|
||||||
|
"U.S. Government End User Purchasers. The Software and Documentation qualify as \"commercial items,\" as that term is defined at Federal Acquisition Regulation (\"FAR\") (48 C.F.R.) 2.101, consisting of \"commercial computer software\" and \"commercial computer software documentation\" as such terms are used in FAR 12.212. Consistent with FAR 12.212 and DoD FAR Supp. 227.7202-1 through 227.7202-4, and notwithstanding any other FAR or other contractual clause to the contrary in any agreement into which the Agreement may be incorporated, Customer may provide to Government end user or, if the Agreement is direct, Government end user will acquire, the Software and Documentation with only those rights set forth in the Agreement. Use of either the Software or Documentation or both constitutes agreement by the Government that the Software and Documentation are \"commercial computer software\" and \"commercial computer " +
|
||||||
|
"software documentation,\" and constitutes acceptance of the rights and restrictions herein.\n" +
|
||||||
|
"\n" +
|
||||||
|
"Identified Components; Additional Terms. The Software may contain or be delivered with one or more components, which may include third-party components, identified by Cisco in the Documentation, readme.txt file, third-party click-accept or elsewhere (e.g. on www.cisco.com) (the \"Identified Component(s)\") as being subject to different license agreement terms, disclaimers of warranties, limited warranties or other terms and conditions (collectively, \"Additional Terms\") than those set forth herein. You agree to the applicable Additional Terms for any such Identified Component(s).\n" +
|
||||||
|
"\n" +
|
||||||
|
"Limited Warranty\n" +
|
||||||
|
"\n" +
|
||||||
|
"Subject to the limitations and conditions set forth herein, Cisco warrants that commencing from the date of shipment to Customer (but in case of resale by an Approved Source other than Cisco, commencing not more than ninety (90) days after original shipment by Cisco), and continuing for a period of the longer of (a) ninety (90) days or (b) the warranty period (if any) expressly set forth as applicable specifically to software in the warranty card accompanying the product of which the Software is a part (the \"Product\") (if any): (a) the media on which the Software is furnished will be free of defects in materials and workmanship under normal use; and (b) the Software substantially conforms to the Documentation. The date of shipment of a Product by Cisco is set forth on the packaging material in which the Product is shipped. Except for the foregoing, the Software is provided \"AS IS\". This limited warranty extends only to the " +
|
||||||
|
"Software purchased from an Approved Source by a Customer who is the first registered end user. Customer's sole and exclusive remedy and the entire liability of Cisco and its suppliers under this limited warranty will be (i) replacement of defective media and/or (ii) at Cisco's option, repair, replacement, or refund of the purchase price of the Software, in both cases subject to the condition that any error or defect constituting a breach of this limited warranty is reported to the Approved Source supplying the Software to Customer, within the warranty period. Cisco or the Approved Source supplying the Software to Customer may, at its option, require return of the Software and/or Documentation as a condition to the remedy. In no event does Cisco warrant that the Software is error free or that Customer will be able to operate the Software without problems or interruptions. In addition, due to the continual development of new " +
|
||||||
|
"techniques for intruding upon and attacking networks, Cisco does not warrant that the Software or any equipment, system or network on which the Software is used will be free of vulnerability to intrusion or attack.\n" +
|
||||||
|
"\n" +
|
||||||
|
"Restrictions. This warranty does not apply if the Software, Product or any other equipment upon which the Software is authorized to be used (a) has been altered, except by Cisco or its authorized representative, (b) has not been installed, operated, repaired, or maintained in accordance with instructions supplied by Cisco, (c) has been subjected to abnormal physical or electrical stress, abnormal environmental conditions, misuse, negligence, or accident; or (d) is licensed for beta, evaluation, testing or demonstration purposes. The Software warranty also does not apply to (e) any temporary Software modules; (f) any Software not posted on Cisco's Software Center; (g) any Software that Cisco expressly provides on an \"AS IS\" basis on Cisco's Software Center; (h) any Software for which an Approved Source does not receive a license fee; and (i) Software supplied by any third party which is not an Approved Source.\n" +
|
||||||
|
"\n" +
|
||||||
|
"DISCLAIMER OF WARRANTY\n" +
|
||||||
|
"\n" +
|
||||||
|
"EXCEPT AS SPECIFIED IN THIS WARRANTY SECTION, ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS, AND WARRANTIES INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTY OR CONDITION OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, SATISFACTORY QUALITY, NON-INTERFERENCE, ACCURACY OF INFORMATIONAL CONTENT, OR ARISING FROM A COURSE OF DEALING, LAW, USAGE, OR TRADE PRACTICE, ARE HEREBY EXCLUDED TO THE EXTENT ALLOWED BY APPLICABLE LAW AND ARE EXPRESSLY DISCLAIMED BY CISCO, ITS SUPPLIERS AND LICENSORS. TO THE EXTENT THAT ANY OF THE SAME CANNOT BE EXCLUDED, SUCH IMPLIED CONDITION, REPRESENTATION AND/OR WARRANTY IS LIMITED IN DURATION TO THE EXPRESS WARRANTY PERIOD REFERRED TO IN THE \"LIMITED WARRANTY\" SECTION ABOVE. BECAUSE SOME STATES OR JURISDICTIONS DO NOT ALLOW LIMITATIONS ON HOW LONG AN IMPLIED WARRANTY LASTS, THE ABOVE LIMITATION MAY NOT APPLY IN SUCH STATES. THIS WARRANTY GIVES CUSTOMER SPECIFIC LEGAL RIGHTS, " +
|
||||||
|
"AND CUSTOMER MAY ALSO HAVE OTHER RIGHTS WHICH VARY FROM JURISDICTION TO JURISDICTION. This disclaimer and exclusion shall apply even if the express warranty set forth above fails of its essential purpose.\n" +
|
||||||
|
"\n" +
|
||||||
|
"Disclaimer of Liabilities-Limitation of Liability. IF YOU ACQUIRED THE SOFTWARE IN THE UNITED STATES, LATIN AMERICA, CANADA, JAPAN OR THE CARIBBEAN, NOTWITHSTANDING ANYTHING ELSE IN THE AGREEMENT TO THE CONTRARY, ALL LIABILITY OF CISCO, ITS AFFILIATES, OFFICERS, DIRECTORS, EMPLOYEES, AGENTS, SUPPLIERS AND LICENSORS COLLECTIVELY, TO CUSTOMER, WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE), BREACH OF WARRANTY OR OTHERWISE, SHALL NOT EXCEED THE PRICE PAID BY CUSTOMER TO ANY APPROVED SOURCE FOR THE SOFTWARE THAT GAVE RISE TO THE CLAIM OR IF THE SOFTWARE IS PART OF ANOTHER PRODUCT, THE PRICE PAID FOR SUCH OTHER PRODUCT. THIS LIMITATION OF LIABILITY FOR SOFTWARE IS CUMULATIVE AND NOT PER INCIDENT (I.E. THE EXISTENCE OF TWO OR MORE CLAIMS WILL NOT ENLARGE THIS LIMIT).\n" +
|
||||||
|
"\n" +
|
||||||
|
"IF YOU ACQUIRED THE SOFTWARE IN EUROPE, THE MIDDLE EAST, AFRICA, ASIA OR OCEANIA, NOTWITHSTANDING ANYTHING ELSE IN THE AGREEMENT TO THE CONTRARY, ALL LIABILITY OF CISCO, ITS AFFILIATES, OFFICERS, DIRECTORS, EMPLOYEES, AGENTS, SUPPLIERS AND LICENSORS COLLECTIVELY, TO CUSTOMER, WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE), BREACH OF WARRANTY OR OTHERWISE, SHALL NOT EXCEED THE PRICE PAID BY CUSTOMER TO CISCO FOR THE SOFTWARE THAT GAVE RISE TO THE CLAIM OR IF THE SOFTWARE IS PART OF ANOTHER PRODUCT, THE PRICE PAID FOR SUCH OTHER PRODUCT. THIS LIMITATION OF LIABILITY FOR SOFTWARE IS CUMULATIVE AND NOT PER INCIDENT (I.E. THE EXISTENCE OF TWO OR MORE CLAIMS WILL NOT ENLARGE THIS LIMIT). NOTHING IN THE AGREEMENT SHALL LIMIT (I) THE LIABILITY OF CISCO, ITS AFFILIATES, OFFICERS, DIRECTORS, EMPLOYEES, AGENTS, SUPPLIERS AND LICENSORS TO CUSTOMER FOR PERSONAL INJURY OR DEATH CAUSED BY THEIR NEGLIGENCE, (II) CISCO'S LIABILITY FOR FRAUDULENT" +
|
||||||
|
" MISREPRESENTATION, OR (III) ANY LIABILITY OF CISCO WHICH CANNOT BE EXCLUDED UNDER APPLICABLE LAW.\n" +
|
||||||
|
"\n" +
|
||||||
|
"Disclaimer of Liabilities-Waiver of Consequential Damages and Other Losses. IF YOU ACQUIRED THE SOFTWARE IN THE UNITED STATES, LATIN AMERICA, THE CARIBBEAN OR CANADA, REGARDLESS OF WHETHER ANY REMEDY SET FORTH HEREIN FAILS OF ITS ESSENTIAL PURPOSE OR OTHERWISE, IN NO EVENT WILL CISCO OR ITS SUPPLIERS BE LIABLE FOR ANY LOST REVENUE, PROFIT, OR LOST OR DAMAGED DATA, BUSINESS INTERRUPTION, LOSS OF CAPITAL, OR FOR SPECIAL, INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR PUNITIVE DAMAGES HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY OR WHETHER ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE OR OTHERWISE AND EVEN IF CISCO OR ITS SUPPLIERS OR LICENSORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. BECAUSE SOME STATES OR JURISDICTIONS DO NOT ALLOW LIMITATION OR EXCLUSION OF CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY NOT APPLY TO YOU.\n" +
|
||||||
|
"\n" +
|
||||||
|
"IF YOU ACQUIRED THE SOFTWARE IN JAPAN, EXCEPT FOR LIABILITY ARISING OUT OF OR IN CONNECTION WITH DEATH OR PERSONAL INJURY, FRAUDULENT MISREPRESENTATION, AND REGARDLESS OF WHETHER ANY REMEDY SET FORTH HEREIN FAILS OF ITS ESSENTIAL PURPOSE OR OTHERWISE, IN NO EVENT WILL CISCO, ITS AFFILIATES, OFFICERS, DIRECTORS, EMPLOYEES, AGENTS, SUPPLIERS AND LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT, OR LOST OR DAMAGED DATA, BUSINESS INTERRUPTION, LOSS OF CAPITAL, OR FOR SPECIAL, INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR PUNITIVE DAMAGES HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY OR WHETHER ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE OR OTHERWISE AND EVEN IF CISCO OR ANY APPROVED SOURCE OR THEIR SUPPLIERS OR LICENSORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n" +
|
||||||
|
"\n" +
|
||||||
|
"IF YOU ACQUIRED THE SOFTWARE IN EUROPE, THE MIDDLE EAST, AFRICA, ASIA OR OCEANIA, IN NO EVENT WILL CISCO, ITS AFFILIATES, OFFICERS, DIRECTORS, EMPLOYEES, AGENTS, SUPPLIERS AND LICENSORS, BE LIABLE FOR ANY LOST REVENUE, LOST PROFIT, OR LOST OR DAMAGED DATA, BUSINESS INTERRUPTION, LOSS OF CAPITAL, OR FOR SPECIAL, INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR PUNITIVE DAMAGES, HOWSOEVER ARISING, INCLUDING, WITHOUT LIMITATION, IN CONTRACT, TORT (INCLUDING NEGLIGENCE) OR WHETHER ARISING OUT OF THE USE OF OR INABILITY TO USE THE SOFTWARE, EVEN IF, IN EACH CASE, CISCO, ITS AFFILIATES, OFFICERS, DIRECTORS, EMPLOYEES, AGENTS, SUPPLIERS AND LICENSORS, HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. BECAUSE SOME STATES OR JURISDICTIONS DO NOT ALLOW LIMITATION OR EXCLUSION OF CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY NOT FULLY APPLY TO YOU. THE FOREGOING EXCLUSION SHALL NOT APPLY TO ANY LIABILITY ARISING OUT OF OR IN " +
|
||||||
|
"CONNECTION WITH: (I) DEATH OR PERSONAL INJURY, (II) FRAUDULENT MISREPRESENTATION, OR (III) CISCO'S LIABILITY IN CONNECTION WITH ANY TERMS THAT CANNOT BE EXCLUDED UNDER APPLICABLE LAW.\n" +
|
||||||
|
"\n" +
|
||||||
|
"Customer acknowledges and agrees that Cisco has set its prices and entered into the Agreement in reliance upon the disclaimers of warranty and the limitations of liability set forth herein, that the same reflect an allocation of risk between the parties (including the risk that a contract remedy may fail of its essential purpose and cause consequential loss), and that the same form an essential basis of the bargain between the parties.\n" +
|
||||||
|
"\n" +
|
||||||
|
"Controlling Law, Jurisdiction. If you acquired, by reference to the address on the purchase order accepted by the Approved Source, the Software in the United States, Latin America, or the Caribbean, the Agreement and warranties (\"Warranties\") are controlled by and construed under the laws of the State of California, United States of America, notwithstanding any conflicts of law provisions; and the state and federal courts of California shall have exclusive jurisdiction over any claim arising under the Agreement or Warranties. If you acquired the Software in Canada, unless expressly prohibited by local law, the Agreement and Warranties are controlled by and construed under the laws of the Province of Ontario, Canada, notwithstanding any conflicts of law provisions; and the courts of the Province of Ontario shall have exclusive jurisdiction over any claim arising under the Agreement or Warranties. If you acquired the Software in " +
|
||||||
|
"Europe, the Middle East, Africa, Asia or Oceania (excluding Australia), unless expressly prohibited by local law, the Agreement and Warranties are controlled by and construed under the laws of England, notwithstanding any conflicts of law provisions; and the English courts shall have exclusive jurisdiction over any claim arising under the Agreement or Warranties. In addition, if the Agreement is controlled by the laws of England, no person who is not a party to the Agreement shall be entitled to enforce or take the benefit of any of its terms under the Contracts (Rights of Third Parties) Act 1999. If you acquired the Software in Japan, unless expressly prohibited by local law, the Agreement and Warranties are controlled by and construed under the laws of Japan, notwithstanding any conflicts of law provisions; and the Tokyo District Court of Japan shall have exclusive jurisdiction over any claim arising under the Agreement or Warranties. " +
|
||||||
|
"If you acquired the Software in Australia, unless expressly prohibited by local law, the Agreement and Warranties are controlled by and construed under the laws of the State of New South Wales, Australia, notwithstanding any conflicts of law provisions; and the State and federal courts of New South Wales shall have exclusive jurisdiction over any claim arising under the Agreement or Warranties. If you acquired the Software in any other country, unless expressly prohibited by local law, the Agreement and Warranties are controlled by and construed under the laws of the State of California, United States of America, notwithstanding any conflicts of law provisions; and the state and federal courts of California shall have exclusive jurisdiction over any claim arising under the Agreement or Warranties.\n" +
|
||||||
|
"\n" +
|
||||||
|
"For all countries referred to above, the parties specifically disclaim the application of the UN Convention on Contracts for the International Sale of Goods. Notwithstanding the foregoing, either party may seek interim injunctive relief in any court of appropriate jurisdiction with respect to any alleged breach of such party's intellectual property or proprietary rights. If any portion hereof is found to be void or unenforceable, the remaining provisions of the Agreement and Warranties shall remain in full force and effect. Except as expressly provided herein, the Agreement constitutes the entire agreement between the parties with respect to the license of the Software and Documentation and supersedes any conflicting or additional terms contained in any Purchase Order or elsewhere, all of which terms are excluded. The Agreement has been written in the English language, and the parties agree that the English version will govern.\n" +
|
||||||
|
"\n" +
|
||||||
|
"Product warranty terms and other information applicable to Cisco products are available at the following URL: www.cisco.com/go/warranty\n" +
|
||||||
|
"\n" +
|
||||||
|
"Cisco and the Cisco logo are trademarks or registered trademarks of Cisco and/or its affiliates in the U.S. and other countries. To view a list of Cisco trademarks, go to this URL: www.cisco.com/go/trademarks. Third-party trademarks mentioned are the property of their respective owners. The use of the word partner does not imply a partnership relationship between Cisco and any other company. (1110R)\n" +
|
||||||
|
"\n" +
|
||||||
|
"© 1998, 2001, 2003, 2008-2014 Cisco Systems, Inc. All rights reserved.</License>\n" +
|
||||||
|
"</EulaSection>\n" +
|
||||||
|
"<EulaSection>\n" +
|
||||||
|
" <Info>supplemental end-user license agreement</Info>\n" +
|
||||||
|
" <License>SUPPLEMENTAL END USER LICENSE AGREEMENT FOR VIRTUAL SOFTWARE PRODUCTS\n" +
|
||||||
|
"\n" +
|
||||||
|
"IMPORTANT: READ CAREFULLY\n" +
|
||||||
|
"\n" +
|
||||||
|
"This Supplemental End User License Agreement (\"SEULA\") contains additional terms and conditions for the Software licensed under the End User License Agreement (\"EULA\") between you and Cisco (collectively, the \"Agreement\"). Capitalized terms used in this SEULA but not defined will have the meanings assigned to them in the EULA. To the extent that there is a conflict between the terms and conditions of the EULA and this SEULA, the terms and conditions of this SEULA will take precedence. In addition to the limitations set forth in the EULA on your access and use of the Software, you agree to comply at all times with the terms and conditions provided in this SEULA.\n" +
|
||||||
|
"\n" +
|
||||||
|
"DOWNLOADING, INSTALLING, OR USING THE SOFTWARE CONSTITUTES ACCEPTANCE OF THE AGREEMENT, AND YOU ARE BINDING YOURSELF AND THE BUSINESS ENTITY THAT YOU REPRESENT (COLLECTIVELY, \"CUSTOMER\") TO THE AGREEMENT. IF YOU DO NOT AGREE TO ALL OF THE TERMS OF THE AGREEMENT, THEN CISCO IS UNWILLING TO LICENSE THE SOFTWARE TO YOU AND (A) YOU MAY NOT DOWNLOAD, INSTALL OR USE THE SOFTWARE, AND (B) YOU MAY RETURN THE SOFTWARE (INCLUDING ANY UNOPENED CD PACKAGE AND ANY WRITTEN MATERIALS) FOR A FULL REFUND, OR, IF THE SOFTWARE AND WRITTEN MATERIALS ARE SUPPLIED AS PART OF ANOTHER PRODUCT, YOU MAY RETURN THE ENTIRE PRODUCT FOR A FULL REFUND. YOUR RIGHT TO RETURN AND REFUND EXPIRES 30 DAYS AFTER PURCHASE FROM CISCO OR AN AUTHORIZED CISCO RESELLER, AND APPLIES ONLY IF YOU ARE THE ORIGINAL END USER PURCHASER.\n" +
|
||||||
|
"\n" +
|
||||||
|
"Definitions\n" +
|
||||||
|
"\"CPU\" means a central processing unit that encompasses part of a Server.\n" +
|
||||||
|
"\"Failover Pair\" means a primary Instance and a standby Instance with the same Software configuration where the standby Instance can take over in case of failure of the primary Instance.\n" +
|
||||||
|
"\"Instance\" means a single copy of the Software. Each copy of the Software loaded into memory is an Instance.\n" +
|
||||||
|
"\"Server\" means a single physical computer or device on a network that manages or provides network resources for multiple users.\n" +
|
||||||
|
"\"Service Provider\" means a company that provides information technology services to external end user customers.\n" +
|
||||||
|
"\"Software\" means Cisco's Adaptive Security Virtual Appliance (\"ASAv\"), Adaptive Security Appliance 1000V Cloud Firewall Software (\"ASA 1000V\"), Nexus 1000V series switch products, Virtual Security Gateway products, or other Cisco virtual software products that Cisco includes under this SEULA.\n" +
|
||||||
|
"\"vCPU\" means a virtual central processing resource assigned to the VM by the underlying virtualization technology.\n" +
|
||||||
|
"\"Virtual Machine\" or \"VM\" means a software container that can run its own operating system and execute applications like a Server.\n" +
|
||||||
|
"\n" +
|
||||||
|
"Additional License Terms and Conditions\n" +
|
||||||
|
"1. Cisco hereby grants Customer the right to install and use the Software on single or multiple Cisco or non-Cisco Servers or on Virtual Machines. In order to use the Software Customer may be required to input a registration number or product activation key and register each Instance online at Cisco's website in order to obtain the necessary entitlements.\n" +
|
||||||
|
"2. Customer shall pay a unit license fee to Cisco or an authorized Cisco reseller, as applicable, for each Instance installed on a Cisco or non-Cisco Server CPU, vCPU or Virtual Machine, as determined by Cisco.\n" +
|
||||||
|
"3. For the ASA 1000V, Customer is licensed the number of Instances equal to the number of CPUs covered by the unit license fee. If Customer deploys a Failover Pair, then the fee for the additional standby Instance is included in the fee for each primary Instance.\n" +
|
||||||
|
"4. If Customer is a Service Provider, Customer may use the Software under the terms of this Agreement for the purpose of delivering hosted information technology services to Customer's end user customers, subject to payment of the required license fee(s).\n" +
|
||||||
|
"5. Customer may also use the Software under the terms of this Agreement to deliver hosted information technology services to Customer affiliates, subject to payment of the required license fee(s).\n" +
|
||||||
|
"6. If the Software is subject to Cisco's Smart Licensing program, Cisco will be able to assess if Customer is using the Software within the limits and entitlements paid for by Customer. If the Smart Licensing program is applicable, Customer will be required to enter into a separate terms of service agreement relating to Smart Licensing.</License>\n" +
|
||||||
|
"</EulaSection>\n" +
|
||||||
|
"</VirtualSystem>";
|
||||||
|
|
||||||
|
private String productSectionWithCategories =
|
||||||
|
"<VirtualSystem ovf:id=\"VMware-vCenter-Server-Appliance\">\n" +
|
||||||
|
"<ProductSection ovf:required=\"false\">\n" +
|
||||||
|
" <Info>Appliance ISV branding information</Info>\n" +
|
||||||
|
" <Product>VMware vCenter Server Appliance</Product>\n" +
|
||||||
|
" <Vendor>VMware Inc.</Vendor>\n" +
|
||||||
|
" <!--\n" +
|
||||||
|
" Version is the actual product version in the\n" +
|
||||||
|
" form X.X.X.X where X is an unsigned 16-bit integer.\n" +
|
||||||
|
"\n" +
|
||||||
|
" FullVersion is a descriptive version string\n" +
|
||||||
|
" including, for example, alpha or beta designations\n" +
|
||||||
|
" and other release criteria.\n" +
|
||||||
|
" -->\n" +
|
||||||
|
"\n" +
|
||||||
|
"\n" +
|
||||||
|
" <Version>6.7.0.44000</Version>\n" +
|
||||||
|
" <FullVersion>6.7.0.44000 build 16046470</FullVersion>\n" +
|
||||||
|
" <ProductUrl/>\n" +
|
||||||
|
" <VendorUrl>http://www.vmware.com</VendorUrl>\n" +
|
||||||
|
" <AppUrl>https://${vami.ip0.VMware_vCenter_Server_Appliance}:5480/</AppUrl>\n" +
|
||||||
|
" <Category>Application</Category>\n" +
|
||||||
|
" <Category vmw:uioptional=\"false\">Networking Configuration</Category>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.appliance.net.addr.family\" ovf:type=\"string\" ovf:userConfigurable=\"true\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Host Network IP Address Family</Label>\n" +
|
||||||
|
" <Description>Network IP address family (i.e., 'ipv4' or 'ipv6').</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.appliance.net.mode\" ovf:type=\"string\" ovf:userConfigurable=\"true\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Host Network Mode</Label>\n" +
|
||||||
|
" <Description>Network mode (i.e., 'static', 'dhcp', or 'autoconf' (IPv6 only).</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.appliance.net.addr\" ovf:type=\"string\" ovf:userConfigurable=\"true\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Host Network IP Address</Label>\n" +
|
||||||
|
" <Description>Network IP address. Only provide this when mode is 'static'. Can be IPv4 or IPv6 based on specified address family.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.appliance.net.prefix\" ovf:type=\"string\" ovf:userConfigurable=\"true\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Host Network Prefix</Label>\n" +
|
||||||
|
" <Description>Network prefix length. Only provide this when mode is 'static'. 0-32 for IPv4. 0-128 for IPv6.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.appliance.net.gateway\" ovf:type=\"string\" ovf:userConfigurable=\"true\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Host Network Default Gateway</Label>\n" +
|
||||||
|
" <Description>IP address of default gateway. Can be 'default' when using IPv6.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.appliance.net.dns.servers\" ovf:type=\"string\" ovf:userConfigurable=\"true\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Host Network DNS Servers</Label>\n" +
|
||||||
|
" <Description>Comma separated list of IP addresses of DNS servers.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.appliance.net.pnid\" ovf:type=\"string\" ovf:userConfigurable=\"true\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Host Network Identity</Label>\n" +
|
||||||
|
" <Description>Network identity (IP address or fully-qualified domain name) services should use when advertising themselves.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.appliance.net.ports\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"{}\">\n" +
|
||||||
|
" <Label>Custom Network Ports</Label>\n" +
|
||||||
|
" <Description>A string encoding a JSON object mapping port names to port numbers.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Category vmw:uioptional=\"false\">SSO Configuration</Category>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.vmdir.username\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"administrator@vsphere.local\">\n" +
|
||||||
|
" <Label>Directory Username</Label>\n" +
|
||||||
|
" <Description>For the first instance of the identity domain, this is the username with Administrator privileges. Otherwise, this is the username of the replication partner.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.vmdir.password\" ovf:password=\"true\" ovf:type=\"string\" ovf:userConfigurable=\"true\">\n" +
|
||||||
|
" <Label>Directory Password</Label>\n" +
|
||||||
|
" <Description>For the first instance of the identity domain, this is the password given to the Administrator account. Otherwise, this is the password of the Administrator account of the replication partner.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.vmdir.domain-name\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"vsphere.local\">\n" +
|
||||||
|
" <Label>Directory Domain Name</Label>\n" +
|
||||||
|
" <Description>For the first instance of the identity domain, this is the name of the newly created domain.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.vmdir.site-name\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"Default-First-Site\">\n" +
|
||||||
|
" <Label>Site Name</Label>\n" +
|
||||||
|
" <Description>Name of site. Use 'Default-First-Site' to define a new site.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.vmdir.first-instance\" ovf:type=\"boolean\" ovf:userConfigurable=\"false\" ovf:value=\"True\">\n" +
|
||||||
|
" <Label>New Identity Domain</Label>\n" +
|
||||||
|
" <Description>If this parameter is set to True, the VMware directory instance is setup as the first instance of a new identity domain. Otherwise, the instance is setup as a replication partner.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.vmdir.replication-partner-hostname\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Directory Replication Partner</Label>\n" +
|
||||||
|
" <Description>The hostname of the VMware directory replication partner. This value is ignored for the first instance of the identity domain.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Category vmw:uioptional=\"false\">Database Configuration</Category>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.db.type\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"embedded\">\n" +
|
||||||
|
" <Label>Database Type</Label>\n" +
|
||||||
|
" <Description>String indicating whether the database is 'embedded' or 'external'.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.db.user\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Database User</Label>\n" +
|
||||||
|
" <Description>String naming the account to use when connecting to external database (ignored when db.type is 'embedded').</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.db.password\" ovf:password=\"true\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Database Password</Label>\n" +
|
||||||
|
" <Description>String providing the password to use when connecting to external database (ignored when db.type is 'embedded').</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.db.servername\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Database Server</Label>\n" +
|
||||||
|
" <Description>String naming the the hostname of the server on which the external database is running (ignored when db.type is 'embedded').</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.db.serverport\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Database Port</Label>\n" +
|
||||||
|
" <Description>String describing the port on the host on which the external database is running (ignored when db.type is 'embedded').</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.db.provider\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Database Provider</Label>\n" +
|
||||||
|
" <Description>String describing the external database provider. The only supported value is 'oracle' (ignored when the db.type is 'embedded').</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.db.instance\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Database Instance</Label>\n" +
|
||||||
|
" <Description>String describing the external database instance. Values could be anything depending on what the database instance name the DBA creates in the external db. (ignored when the db.type is 'embedded').</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Category vmw:uioptional=\"false\">System Configuration</Category>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.appliance.root.passwd\" ovf:password=\"true\" ovf:type=\"string\" ovf:userConfigurable=\"true\">\n" +
|
||||||
|
" <Label>Root Password</Label>\n" +
|
||||||
|
" <Description>Password to assign to root account. If blank, password can be set on the console.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.appliance.root.shell\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Root Shell</Label>\n" +
|
||||||
|
" <Description>This property is not changeable.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.appliance.ssh.enabled\" ovf:type=\"boolean\" ovf:userConfigurable=\"false\" ovf:value=\"False\">\n" +
|
||||||
|
" <Label>SSH Enabled</Label>\n" +
|
||||||
|
" <Description>Set whether SSH-based remote login is enabled. This configuration can be changed after deployment.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.appliance.time.tools-sync\" ovf:type=\"boolean\" ovf:userConfigurable=\"false\" ovf:value=\"False\">\n" +
|
||||||
|
" <Label>Tools-based Time Synchronization Enabled</Label>\n" +
|
||||||
|
" <Description>Set whether VMware tools based time synchronization should be used. This parameter is ignored if appliance.ntp.servers is not empty.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.appliance.ntp.servers\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>NTP Servers</Label>\n" +
|
||||||
|
" <Description>A comma-seperated list of hostnames or IP addresses of NTP Servers</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.deployment.node.type\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"embedded\">\n" +
|
||||||
|
" <Label>Deployment Type</Label>\n" +
|
||||||
|
" <Description>Type of appliance to deploy (i.e. 'embedded', 'infrastructure' or 'management').</Description>\n" +
|
||||||
|
" <Value ovf:configuration=\"management-xlarge\" ovf:value=\"management\"/>\n" +
|
||||||
|
" <Value ovf:configuration=\"management-large\" ovf:value=\"management\"/>\n" +
|
||||||
|
" <Value ovf:configuration=\"management-medium\" ovf:value=\"management\"/>\n" +
|
||||||
|
" <Value ovf:configuration=\"management-small\" ovf:value=\"management\"/>\n" +
|
||||||
|
" <Value ovf:configuration=\"management-tiny\" ovf:value=\"management\"/>\n" +
|
||||||
|
" <Value ovf:configuration=\"management-xlarge-lstorage\" ovf:value=\"management\"/>\n" +
|
||||||
|
" <Value ovf:configuration=\"management-large-lstorage\" ovf:value=\"management\"/>\n" +
|
||||||
|
" <Value ovf:configuration=\"management-medium-lstorage\" ovf:value=\"management\"/>\n" +
|
||||||
|
" <Value ovf:configuration=\"management-small-lstorage\" ovf:value=\"management\"/>\n" +
|
||||||
|
" <Value ovf:configuration=\"management-tiny-lstorage\" ovf:value=\"management\"/>\n" +
|
||||||
|
" <Value ovf:configuration=\"management-xlarge-xlstorage\" ovf:value=\"management\"/>\n" +
|
||||||
|
" <Value ovf:configuration=\"management-large-xlstorage\" ovf:value=\"management\"/>\n" +
|
||||||
|
" <Value ovf:configuration=\"management-medium-xlstorage\" ovf:value=\"management\"/>\n" +
|
||||||
|
" <Value ovf:configuration=\"management-small-xlstorage\" ovf:value=\"management\"/>\n" +
|
||||||
|
" <Value ovf:configuration=\"management-tiny-xlstorage\" ovf:value=\"management\"/>\n" +
|
||||||
|
" <Value ovf:configuration=\"infrastructure\" ovf:value=\"infrastructure\"/>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.system.vm0.hostname\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Platform Services Controller</Label>\n" +
|
||||||
|
" <Description>When deploying a vCenter Server Node, please provide the FQDN or IP address of a Platform Services Controller (leave blank otherwise). The choice of FQDN versus IP address is decided based on the Platform Services Controller's own notion of its network identity.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.system.vm0.port\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"443\">\n" +
|
||||||
|
" <Label>HTTPS Port on Platform Services Controller</Label>\n" +
|
||||||
|
" <Description>When deploying a vCenter Server pointing to an external platform services controller, please provide the HTTPS port of the external platform services controller if a custom port number is being used. The default HTTPS port number is 443.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Category vmw:uioptional=\"true\">Upgrade Configuration</Category>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.upgrade.source.vpxd.ip\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Upgrade Source Hostname</Label>\n" +
|
||||||
|
" <Description>IP/hostname of the appliance to upgrade. Set only for upgrade.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.upgrade.source.ma.port\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"9123\">\n" +
|
||||||
|
" <Label>Migration Assistant Port</Label>\n" +
|
||||||
|
" <Description>Port used by Migration Assistant on source vCenter Server.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.upgrade.source.vpxd.user\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Upgrade Source vCenter Username</Label>\n" +
|
||||||
|
" <Description>vCenter username for the appliance to upgrade. Set only for upgrade.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.upgrade.source.vpxd.password\" ovf:password=\"true\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Upgrade Source vCenter Password</Label>\n" +
|
||||||
|
" <Description>vCenter password for the appliance to upgrade. Set only for upgrade.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.upgrade.source.guest.user\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Upgrade Source OS Username</Label>\n" +
|
||||||
|
" <Description>Username for the appliance operating system to upgrade. Usually root. Set only for upgrade.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.upgrade.source.guest.password\" ovf:password=\"true\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Upgrade Source OS Password</Label>\n" +
|
||||||
|
" <Description>Password for the appliance operating system to upgrade. Set only for upgrade.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.upgrade.source.guestops.host.addr\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Upgrade Management Host Hostname</Label>\n" +
|
||||||
|
" <Description>URL that consists of the IP address or FQDN and https port of the vCenter Server instance or ESXi host that manages the appliance to upgrade. Https port is an optional parameter which by default is 443. Example: 10.10.10.10, //10.10.10.10:444, //[2001:db8:a0b:12f0::1]:444. Set only for upgrade.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.upgrade.source.guestops.host.user\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Upgrade Management Host Username</Label>\n" +
|
||||||
|
" <Description>Username for the host that manages appliance to upgrade. Can be either vCenter or ESX host. Set only for upgrade.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.upgrade.source.guestops.host.password\" ovf:password=\"true\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Upgrade Management Host Password</Label>\n" +
|
||||||
|
" <Description>Password for the host that manages appliance to upgrade. Can be either vCenter or ESX host. Set only for upgrade.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.upgrade.source.ssl.thumbprint\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Upgrade Management Host Thumbprint</Label>\n" +
|
||||||
|
" <Description>Thumbprint for the SSL certificate of the host that manages the appliance to upgrade. Set only for upgrade.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.upgrade.source.platform\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"linux\">\n" +
|
||||||
|
" <Label>Upgrade Source Platform</Label>\n" +
|
||||||
|
" <Description>Source host platform. Optional. Set only for upgrade</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.upgrade.source.export.directory\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"/var/tmp\">\n" +
|
||||||
|
" <Label>Upgrade Source Export Folder</Label>\n" +
|
||||||
|
" <Description>Folder on the source appliance, where to store migrate data. Optional. Set only for upgrade</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.upgrade.import.directory\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"/storage/seat/cis-export-folder\">\n" +
|
||||||
|
" <Label>Upgrade Destination Export Folder</Label>\n" +
|
||||||
|
" <Description>Folder where exported source data will be stored in the appliance. Optional. Set only for upgrade</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.upgrade.user.options\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Upgrade Advanced Options</Label>\n" +
|
||||||
|
" <Description>Advanced upgrade settings specified in json format. Optional. Set only for upgrade</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.ad.domain-name\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Active Directory domain name</Label>\n" +
|
||||||
|
" <Description>Active Directory domain to join.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.ad.domain.username\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Active Directory domain admin user</Label>\n" +
|
||||||
|
" <Description>Active Directory domain admin user. This username will be used to join the machine to the domain.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.ad.domain.password\" ovf:password=\"true\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Active Directory domain admin user password</Label>\n" +
|
||||||
|
" <Description>Active Directory domain admin user password. This password will be used to join the machine to the domain.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.vpxd.ha.management.addr\" ovf:type=\"string\" ovf:userConfigurable=\"true\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>vCenter Server managing target appliance</Label>\n" +
|
||||||
|
" <Description>FQDN or IP address of the vCenter Server managing that target appliance. Used when upgrading a source appliance in VCHA cluster.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.vpxd.ha.management.port\" ovf:type=\"string\" ovf:userConfigurable=\"true\" ovf:value=\"443\">\n" +
|
||||||
|
" <Label>Port of the vCenter Server managing target appliance</Label>\n" +
|
||||||
|
" <Description>Https port of the vCenter Server managing that target appliance. Used when upgrading a source appliance in VCHA cluster. If not specified, port 443 will be used by default.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.vpxd.ha.management.user\" ovf:type=\"string\" ovf:userConfigurable=\"true\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Username for the vCenter Server managing target appliance</Label>\n" +
|
||||||
|
" <Description>User able to authenticate in vCenter Server managing that target appliance. The user must have the privilege Global.VCServer. Used when upgrading a source appliance in VCHA cluster.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.vpxd.ha.management.password\" ovf:password=\"true\" ovf:type=\"string\" ovf:userConfigurable=\"true\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Password for the vCenter Server managing target appliance</Label>\n" +
|
||||||
|
" <Description>Password for administrator user authenticating to the vCenter Server managing target appliance. Used when upgrading a source appliance in VCHA cluster.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.vpxd.ha.management.thumbprint\" ovf:type=\"string\" ovf:userConfigurable=\"true\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Thumbprint for the SSL certificate of the vCenter Server managing target appliance</Label>\n" +
|
||||||
|
" <Description>Thumbprint for the SSL certificate of the host that manages the appliance to upgrade. Used when upgrading a source appliance in VCHA cluster.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.vpxd.ha.placement\" ovf:type=\"string\" ovf:userConfigurable=\"true\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Path to the compute resource where target appliance will be deployed on management vCenter Server</Label>\n" +
|
||||||
|
" <Description>Path to host/cluster/resource pool where target appliance will be deployed on management vCenter Server. Used when upgrading a source appliance in VCHA cluster. Example: /my_datacenter/my_folder/my_host_or_cluster/my_resource_pool</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Category vmw:uioptional=\"true\">Miscellaneous</Category>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.netdump.enabled\" ovf:type=\"boolean\" ovf:userConfigurable=\"false\" ovf:value=\"True\">\n" +
|
||||||
|
" <Label>ESXi Dump Collector Enabled</Label>\n" +
|
||||||
|
" <Description>Set whether ESXi Dump Collector service is enabled. This configuration can be changed after deployment.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.silentinstall\" ovf:type=\"boolean\" ovf:userConfigurable=\"false\" ovf:value=\"False\">\n" +
|
||||||
|
" <Label>Do Silent Install</Label>\n" +
|
||||||
|
" <Description>If this parameter is set to True, no questions will be posted during install or upgrade. Otherwise, the install process will wait for a reply if there is a pending question.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.clientlocale\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"en\">\n" +
|
||||||
|
" <Label>The Client Locale</Label>\n" +
|
||||||
|
" <Description>This parameter specifies the client locale. Supported locales are en, fr, ja, ko, zh_CN and zh_TW. English is assumed if locale is unknown.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.feature.states\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>Feature switch states</Label>\n" +
|
||||||
|
" <Description>Specify feature switch states which need to be added or modified in feature switch state config file. Format: key1=value1, key2=value2</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.ceip_enabled\" ovf:type=\"boolean\" ovf:userConfigurable=\"true\" ovf:value=\"False\">\n" +
|
||||||
|
" <Label>CEIP enabled</Label>\n" +
|
||||||
|
" <Description>VMware’s Customer Experience Improvement Program ("CEIP") provides VMware with information that enables VMware to improve its products and services, to fix problems, and to advise you on how best to deploy and use our products. As part of the CEIP, VMware collects technical information about your organization’s use of VMware products and services on a regular basis in association with your organization’s VMware license key(s). This information does not personally identify any individual. For more details about the Program and how VMware uses the information it collects through CEIP, please see the product documentation at http://www.vmware.com/info?id=1399. If you want to participate in VMware’s CEIP for this product, set this property to True. You may join or leave VMware’s CEIP for this product at any time.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.deployment.autoconfig\" ovf:type=\"boolean\" ovf:userConfigurable=\"false\" ovf:value=\"False\">\n" +
|
||||||
|
" <Label>Auto Start Services</Label>\n" +
|
||||||
|
" <Description>If this parameter is set to True, the appliance will be configured after deployment using the specified OVF configuration parameters. If set to False, the appliance should be configured post-deployment using the VMware Appliance Management Interface.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.vpxd.mac-allocation-scheme.prefix\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>MAC address allocation scheme prefix</Label>\n" +
|
||||||
|
" <Description>If a valid MAC address prefix is provided, then all MAC addresses assigned by vCenter Server will begin with this prefix instead of the VMware OUI. This property cannot co-exist with mac-allocation-scheme.ranges</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.vpxd.mac-allocation-scheme.prefix-length\" ovf:type=\"uint8\" ovf:userConfigurable=\"false\" ovf:value=\"0\">\n" +
|
||||||
|
" <Label>MAC address allocation scheme prefix length</Label>\n" +
|
||||||
|
" <Description>This property is mandatory whenever a custom MAC prefix is provided.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"guestinfo.cis.vpxd.mac-allocation-scheme.ranges\" ovf:type=\"string\" ovf:userConfigurable=\"false\" ovf:value=\"\">\n" +
|
||||||
|
" <Label>MAC address allocation scheme ranges</Label>\n" +
|
||||||
|
" <Description>If valid MAC address range is provided, then vCenter Server will assign MAC addresses from this range instead of allocating VMware OUI based MAC address. The address range must be provided in the format "BeginAddress1-EndAddress1,...,BeginAddressN-EndAddressN". This property cannot co-exist with mac-allocation-scheme.prefix.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
"</ProductSection>\n" +
|
||||||
|
"<ProductSection ovf:class=\"vami\" ovf:instance=\"VMware-vCenter-Server-Appliance\" ovf:required=\"false\">\n" +
|
||||||
|
" <Info>VAMI Properties</Info>\n" +
|
||||||
|
" <Category>Networking Properties</Category>\n" +
|
||||||
|
" <Property ovf:key=\"domain\" ovf:type=\"string\" ovf:userConfigurable=\"true\">\n" +
|
||||||
|
" <Label>Domain Name</Label>\n" +
|
||||||
|
" <Description>The domain name of this VM. Leave blank if DHCP is desired.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
" <Property ovf:key=\"searchpath\" ovf:type=\"string\" ovf:userConfigurable=\"true\">\n" +
|
||||||
|
" <Label>Domain Search Path</Label>\n" +
|
||||||
|
" <Description>The domain search path (comma or space separated domain names) for this VM. Leave blank if DHCP is desired.</Description>\n" +
|
||||||
|
" </Property>\n" +
|
||||||
|
"</ProductSection>\n" +
|
||||||
|
"<ProductSection ovf:class=\"vm\" ovf:required=\"false\">\n" +
|
||||||
|
" <Info>VM specific properties</Info>\n" +
|
||||||
|
" <Property ovf:key=\"vmname\" ovf:type=\"string\" ovf:value=\"VMware-vCenter-Server-Appliance\"/>\n" +
|
||||||
|
"</ProductSection>\n" +
|
||||||
|
"</VirtualSystem>";
|
||||||
|
|
||||||
private OVFHelper ovfHelper = new OVFHelper();
|
private OVFHelper ovfHelper = new OVFHelper();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetOVFPropertiesValidOVF() throws IOException, SAXException, ParserConfigurationException {
|
public void testGetOVFPropertiesValidOVF() throws IOException, SAXException, ParserConfigurationException {
|
||||||
List<OVFPropertyTO> props = ovfHelper.getOVFPropertiesXmlString(ovfFileProductSection);
|
List<OVFPropertyTO> props = ovfHelper.getOVFPropertiesFromXmlString(ovfFileProductSection);
|
||||||
Assert.assertEquals(2, props.size());
|
Assert.assertEquals(2, props.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = SAXParseException.class)
|
@Test(expected = SAXParseException.class)
|
||||||
public void testGetOVFPropertiesInvalidOVF() throws IOException, SAXException, ParserConfigurationException {
|
public void testGetOVFPropertiesInvalidOVF() throws IOException, SAXException, ParserConfigurationException {
|
||||||
ovfHelper.getOVFPropertiesXmlString(ovfFileProductSection + "xxxxxxxxxxxxxxxxx");
|
ovfHelper.getOVFPropertiesFromXmlString(ovfFileProductSection + "xxxxxxxxxxxxxxxxx");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetOVFDeploymentOptionsValidOVF() throws IOException, SAXException, ParserConfigurationException {
|
||||||
|
List<OVFConfigurationTO> options = ovfHelper.getOVFDeploymentOptionsFromXmlString(ovfFileDeploymentOptionsSection);
|
||||||
|
Assert.assertEquals(3, options.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetOVFVirtualHardwareSectionValidOVF() throws IOException, SAXException, ParserConfigurationException {
|
||||||
|
List<OVFVirtualHardwareItemTO> items = ovfHelper.getOVFVirtualHardwareSectionFromXmlString(ovfFileVirtualHardwareSection);
|
||||||
|
Assert.assertEquals(20, items.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetOVFEulaSectionValidOVF() throws IOException, SAXException, ParserConfigurationException {
|
||||||
|
List<OVFEulaSectionTO> eulas = ovfHelper.getOVFEulaSectionFromXmlString(eulaSections);
|
||||||
|
Assert.assertEquals(2, eulas.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetOVFPropertiesWithCategories() throws IOException, SAXException, ParserConfigurationException {
|
||||||
|
List<OVFPropertyTO> props = ovfHelper.getOVFPropertiesFromXmlString(productSectionWithCategories);
|
||||||
|
Assert.assertEquals(18, props.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,9 +51,5 @@
|
|||||||
<groupId>commons-codec</groupId>
|
<groupId>commons-codec</groupId>
|
||||||
<artifactId>commons-codec</artifactId>
|
<artifactId>commons-codec</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.commons</groupId>
|
|
||||||
<artifactId>commons-compress</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@ -25,8 +25,10 @@ import java.util.List;
|
|||||||
import com.cloud.agent.api.Answer;
|
import com.cloud.agent.api.Answer;
|
||||||
import com.cloud.agent.api.Command;
|
import com.cloud.agent.api.Command;
|
||||||
import com.cloud.agent.api.LogLevel;
|
import com.cloud.agent.api.LogLevel;
|
||||||
|
import com.cloud.agent.api.to.DatadiskTO;
|
||||||
import com.cloud.storage.VMTemplateStorageResourceAssoc;
|
import com.cloud.storage.VMTemplateStorageResourceAssoc;
|
||||||
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
|
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
|
||||||
|
import org.apache.cloudstack.api.net.NetworkPrerequisiteTO;
|
||||||
|
|
||||||
public class DownloadAnswer extends Answer {
|
public class DownloadAnswer extends Answer {
|
||||||
private String jobId;
|
private String jobId;
|
||||||
@ -38,8 +40,17 @@ public class DownloadAnswer extends Answer {
|
|||||||
private long templateSize = 0L;
|
private long templateSize = 0L;
|
||||||
private long templatePhySicalSize = 0L;
|
private long templatePhySicalSize = 0L;
|
||||||
private String checkSum;
|
private String checkSum;
|
||||||
|
|
||||||
@LogLevel(LogLevel.Log4jLevel.Off)
|
@LogLevel(LogLevel.Log4jLevel.Off)
|
||||||
private List<OVFPropertyTO> ovfProperties;
|
private List<OVFPropertyTO> ovfProperties;
|
||||||
|
@LogLevel(LogLevel.Log4jLevel.Off)
|
||||||
|
private List<NetworkPrerequisiteTO> networkRequirements;
|
||||||
|
@LogLevel(LogLevel.Log4jLevel.Off)
|
||||||
|
private List<DatadiskTO> disks;
|
||||||
|
@LogLevel(LogLevel.Log4jLevel.Off)
|
||||||
|
private OVFVirtualHardwareSectionTO ovfHardwareSection;
|
||||||
|
@LogLevel(LogLevel.Log4jLevel.Off)
|
||||||
|
private List<OVFEulaSectionTO> eulaSections;
|
||||||
|
|
||||||
public String getCheckSum() {
|
public String getCheckSum() {
|
||||||
return checkSum;
|
return checkSum;
|
||||||
@ -157,4 +168,36 @@ public class DownloadAnswer extends Answer {
|
|||||||
public void setOvfProperties(List<OVFPropertyTO> ovfProperties) {
|
public void setOvfProperties(List<OVFPropertyTO> ovfProperties) {
|
||||||
this.ovfProperties = ovfProperties;
|
this.ovfProperties = ovfProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<NetworkPrerequisiteTO> getNetworkRequirements() {
|
||||||
|
return networkRequirements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNetworkRequirements(List<NetworkPrerequisiteTO> networkRequirements) {
|
||||||
|
this.networkRequirements = networkRequirements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DatadiskTO> getDisks() {
|
||||||
|
return disks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisks(List<DatadiskTO> disks) {
|
||||||
|
this.disks = disks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OVFVirtualHardwareSectionTO getOvfHardwareSection() {
|
||||||
|
return ovfHardwareSection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOvfHardwareSection(OVFVirtualHardwareSectionTO ovfHardwareSection) {
|
||||||
|
this.ovfHardwareSection = ovfHardwareSection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<OVFEulaSectionTO> getEulaSections() {
|
||||||
|
return eulaSections;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEulaSections(List<OVFEulaSectionTO> eulaSections) {
|
||||||
|
this.eulaSections = eulaSections;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,10 +21,12 @@ import com.cloud.agent.api.to.DataTO;
|
|||||||
|
|
||||||
public final class GetDatadisksCommand extends Command {
|
public final class GetDatadisksCommand extends Command {
|
||||||
private DataTO data;
|
private DataTO data;
|
||||||
|
private String configurationId;
|
||||||
|
|
||||||
public GetDatadisksCommand(DataTO data) {
|
public GetDatadisksCommand(DataTO data, String configurationId) {
|
||||||
super();
|
super();
|
||||||
this.data = data;
|
this.data = data;
|
||||||
|
this.configurationId = configurationId;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected GetDatadisksCommand() {
|
protected GetDatadisksCommand() {
|
||||||
@ -40,4 +42,7 @@ public final class GetDatadisksCommand extends Command {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getConfigurationId() {
|
||||||
|
return configurationId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -31,6 +31,7 @@ import com.cloud.utils.component.Manager;
|
|||||||
* ServerResource is a generic container to execute commands sent
|
* ServerResource is a generic container to execute commands sent
|
||||||
*/
|
*/
|
||||||
public interface ServerResource extends Manager {
|
public interface ServerResource extends Manager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Host.Type type of the computing server we have.
|
* @return Host.Type type of the computing server we have.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -34,6 +34,9 @@ import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand;
|
|||||||
import com.cloud.agent.api.Answer;
|
import com.cloud.agent.api.Answer;
|
||||||
|
|
||||||
public interface StorageProcessor {
|
public interface StorageProcessor {
|
||||||
|
|
||||||
|
String REQUEST_TEMPLATE_RELOAD = "request template reload";
|
||||||
|
|
||||||
public Answer copyTemplateToPrimaryStorage(CopyCommand cmd);
|
public Answer copyTemplateToPrimaryStorage(CopyCommand cmd);
|
||||||
|
|
||||||
public Answer cloneVolumeFromBaseTemplate(CopyCommand cmd);
|
public Answer cloneVolumeFromBaseTemplate(CopyCommand cmd);
|
||||||
|
|||||||
@ -20,13 +20,20 @@
|
|||||||
package com.cloud.storage.template;
|
package com.cloud.storage.template;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.storage.OVFConfigurationTO;
|
||||||
|
import com.cloud.agent.api.storage.OVFEulaSectionTO;
|
||||||
import com.cloud.agent.api.storage.OVFPropertyTO;
|
import com.cloud.agent.api.storage.OVFPropertyTO;
|
||||||
|
import com.cloud.agent.api.storage.OVFVirtualHardwareItemTO;
|
||||||
|
import com.cloud.agent.api.storage.OVFVirtualHardwareSectionTO;
|
||||||
|
import org.apache.cloudstack.api.net.NetworkPrerequisiteTO;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
@ -41,9 +48,13 @@ import com.cloud.storage.StorageLayer;
|
|||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.component.AdapterBase;
|
import com.cloud.utils.component.AdapterBase;
|
||||||
import com.cloud.utils.script.Script;
|
import com.cloud.utils.script.Script;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* processes the content of an OVA for registration of a template
|
||||||
|
*/
|
||||||
public class OVAProcessor extends AdapterBase implements Processor {
|
public class OVAProcessor extends AdapterBase implements Processor {
|
||||||
private static final Logger s_logger = Logger.getLogger(OVAProcessor.class);
|
private static final Logger LOGGER = Logger.getLogger(OVAProcessor.class);
|
||||||
StorageLayer _storage;
|
StorageLayer _storage;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -53,73 +64,137 @@ public class OVAProcessor extends AdapterBase implements Processor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FormatInfo process(String templatePath, ImageFormat format, String templateName, long processTimeout) throws InternalErrorException {
|
public FormatInfo process(String templatePath, ImageFormat format, String templateName, long processTimeout) throws InternalErrorException {
|
||||||
if (format != null) {
|
if (! conversionChecks(format)){
|
||||||
if (s_logger.isInfoEnabled()) {
|
|
||||||
s_logger.info("We currently don't handle conversion from " + format + " to OVA.");
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_logger.info("Template processing. templatePath: " + templatePath + ", templateName: " + templateName);
|
LOGGER.info("Template processing. templatePath: " + templatePath + ", templateName: " + templateName);
|
||||||
String templateFilePath = templatePath + File.separator + templateName + "." + ImageFormat.OVA.getFileExtension();
|
String templateFilePath = templatePath + File.separator + templateName + "." + ImageFormat.OVA.getFileExtension();
|
||||||
if (!_storage.exists(templateFilePath)) {
|
if (!_storage.exists(templateFilePath)) {
|
||||||
if (s_logger.isInfoEnabled()) {
|
if (LOGGER.isInfoEnabled()) {
|
||||||
s_logger.info("Unable to find the vmware template file: " + templateFilePath);
|
LOGGER.info("Unable to find the vmware template file: " + templateFilePath);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_logger.info("Template processing - untar OVA package. templatePath: " + templatePath + ", templateName: " + templateName);
|
String templateFileFullPath = unpackOva(templatePath, templateName, processTimeout);
|
||||||
|
|
||||||
|
setFileSystemAccessRights(templatePath);
|
||||||
|
|
||||||
|
FormatInfo info = createFormatInfo(templatePath, templateName, templateFilePath, templateFileFullPath);
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FormatInfo createFormatInfo(String templatePath, String templateName, String templateFilePath, String templateFileFullPath) throws InternalErrorException {
|
||||||
|
FormatInfo info = new FormatInfo();
|
||||||
|
info.format = ImageFormat.OVA;
|
||||||
|
info.filename = templateName + "." + ImageFormat.OVA.getFileExtension();
|
||||||
|
info.size = _storage.getSize(templateFilePath);
|
||||||
|
info.virtualSize = getTemplateVirtualSize(templatePath, info.filename);
|
||||||
|
validateOva(templateFileFullPath, info);
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* side effect; properties are added to the info
|
||||||
|
*
|
||||||
|
* @throws InternalErrorException on an invalid ova contents
|
||||||
|
*/
|
||||||
|
private void validateOva(String templateFileFullPath, FormatInfo info) throws InternalErrorException {
|
||||||
|
String ovfFilePath = getOVFFilePath(templateFileFullPath);
|
||||||
|
OVFHelper ovfHelper = new OVFHelper();
|
||||||
|
Document doc = ovfHelper.getDocumentFromFile(ovfFilePath);
|
||||||
|
|
||||||
|
List<DatadiskTO> disks = ovfHelper.getOVFVolumeInfoFromFile(ovfFilePath, doc, null);
|
||||||
|
if (LOGGER.isTraceEnabled()) {
|
||||||
|
LOGGER.trace(String.format("Found %d disks in template %s", CollectionUtils.isNotEmpty(disks) ? disks.size() : 0, ovfFilePath));
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isNotEmpty(disks)) {
|
||||||
|
info.disks = disks;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<NetworkPrerequisiteTO> nets = ovfHelper.getNetPrerequisitesFromDocument(doc);
|
||||||
|
if (CollectionUtils.isNotEmpty(nets)) {
|
||||||
|
LOGGER.info("Found " + nets.size() + " prerequisite networks");
|
||||||
|
info.networks = nets;
|
||||||
|
} else if (LOGGER.isTraceEnabled()) {
|
||||||
|
LOGGER.trace(String.format("no net prerequisites found in template %s", ovfFilePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<OVFPropertyTO> ovfProperties = ovfHelper.getConfigurableOVFPropertiesFromDocument(doc);
|
||||||
|
if (CollectionUtils.isNotEmpty(ovfProperties)) {
|
||||||
|
LOGGER.info("Found " + ovfProperties.size() + " configurable OVF properties");
|
||||||
|
info.ovfProperties = ovfProperties;
|
||||||
|
} else if (LOGGER.isTraceEnabled()) {
|
||||||
|
LOGGER.trace(String.format("no ovf properties found in template %s", ovfFilePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
OVFVirtualHardwareSectionTO hardwareSection = ovfHelper.getVirtualHardwareSectionFromDocument(doc);
|
||||||
|
List<OVFConfigurationTO> configurations = hardwareSection.getConfigurations();
|
||||||
|
if (CollectionUtils.isNotEmpty(configurations)) {
|
||||||
|
LOGGER.info("Found " + configurations.size() + " deployment option configurations");
|
||||||
|
}
|
||||||
|
List<OVFVirtualHardwareItemTO> hardwareItems = hardwareSection.getCommonHardwareItems();
|
||||||
|
if (CollectionUtils.isNotEmpty(hardwareItems)) {
|
||||||
|
LOGGER.info("Found " + hardwareItems.size() + " virtual hardware items");
|
||||||
|
}
|
||||||
|
info.hardwareSection = hardwareSection;
|
||||||
|
List<OVFEulaSectionTO> eulaSections = ovfHelper.getEulaSectionsFromDocument(doc);
|
||||||
|
if (CollectionUtils.isNotEmpty(eulaSections)) {
|
||||||
|
LOGGER.info("Found " + eulaSections.size() + " license agreements");
|
||||||
|
info.eulaSections = eulaSections;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setFileSystemAccessRights(String templatePath) {
|
||||||
|
Script command;
|
||||||
|
String result;
|
||||||
|
|
||||||
|
command = new Script("chmod", 0, LOGGER);
|
||||||
|
command.add("-R");
|
||||||
|
command.add("666", templatePath);
|
||||||
|
result = command.execute();
|
||||||
|
if (result != null) {
|
||||||
|
LOGGER.warn("Unable to set permissions for files in " + templatePath + " due to " + result);
|
||||||
|
}
|
||||||
|
command = new Script("chmod", 0, LOGGER);
|
||||||
|
command.add("777", templatePath);
|
||||||
|
result = command.execute();
|
||||||
|
if (result != null) {
|
||||||
|
LOGGER.warn("Unable to set permissions for " + templatePath + " due to " + result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String unpackOva(String templatePath, String templateName, long processTimeout) throws InternalErrorException {
|
||||||
|
LOGGER.info("Template processing - untar OVA package. templatePath: " + templatePath + ", templateName: " + templateName);
|
||||||
String templateFileFullPath = templatePath + File.separator + templateName + "." + ImageFormat.OVA.getFileExtension();
|
String templateFileFullPath = templatePath + File.separator + templateName + "." + ImageFormat.OVA.getFileExtension();
|
||||||
File templateFile = new File(templateFileFullPath);
|
File templateFile = new File(templateFileFullPath);
|
||||||
Script command = new Script("tar", processTimeout, s_logger);
|
Script command = new Script("tar", processTimeout, LOGGER);
|
||||||
command.add("--no-same-owner");
|
command.add("--no-same-owner");
|
||||||
command.add("--no-same-permissions");
|
command.add("--no-same-permissions");
|
||||||
command.add("-xf", templateFileFullPath);
|
command.add("-xf", templateFileFullPath);
|
||||||
command.setWorkDir(templateFile.getParent());
|
command.setWorkDir(templateFile.getParent());
|
||||||
String result = command.execute();
|
String result = command.execute();
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
s_logger.info("failed to untar OVA package due to " + result + ". templatePath: " + templatePath + ", templateName: " + templateName);
|
LOGGER.info("failed to untar OVA package due to " + result + ". templatePath: " + templatePath + ", templateName: " + templateName);
|
||||||
throw new InternalErrorException("failed to untar OVA package");
|
throw new InternalErrorException("failed to untar OVA package");
|
||||||
}
|
}
|
||||||
|
return templateFileFullPath;
|
||||||
command = new Script("chmod", 0, s_logger);
|
|
||||||
command.add("-R");
|
|
||||||
command.add("666", templatePath);
|
|
||||||
result = command.execute();
|
|
||||||
if (result != null) {
|
|
||||||
s_logger.warn("Unable to set permissions for files in " + templatePath + " due to " + result);
|
|
||||||
}
|
|
||||||
command = new Script("chmod", 0, s_logger);
|
|
||||||
command.add("777", templatePath);
|
|
||||||
result = command.execute();
|
|
||||||
if (result != null) {
|
|
||||||
s_logger.warn("Unable to set permissions for " + templatePath + " due to " + result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FormatInfo info = new FormatInfo();
|
private boolean conversionChecks(ImageFormat format) {
|
||||||
info.format = ImageFormat.OVA;
|
if (format != null) {
|
||||||
info.filename = templateName + "." + ImageFormat.OVA.getFileExtension();
|
if (LOGGER.isInfoEnabled()) {
|
||||||
info.size = _storage.getSize(templateFilePath);
|
LOGGER.info("We currently don't handle conversion from " + format + " to OVA.");
|
||||||
info.virtualSize = getTemplateVirtualSize(templatePath, info.filename);
|
|
||||||
|
|
||||||
//vaidate ova
|
|
||||||
String ovfFile = getOVFFilePath(templateFileFullPath);
|
|
||||||
try {
|
|
||||||
OVFHelper ovfHelper = new OVFHelper();
|
|
||||||
List<DatadiskTO> disks = ovfHelper.getOVFVolumeInfo(ovfFile);
|
|
||||||
List<OVFPropertyTO> ovfProperties = ovfHelper.getOVFPropertiesFromFile(ovfFile);
|
|
||||||
if (CollectionUtils.isNotEmpty(ovfProperties)) {
|
|
||||||
s_logger.info("Found " + ovfProperties.size() + " configurable OVF properties");
|
|
||||||
info.ovfProperties = ovfProperties;
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
return false;
|
||||||
s_logger.info("The ovf file " + ovfFile + " is invalid ", e);
|
|
||||||
throw new InternalErrorException("OVA package has bad ovf file " + e.getMessage(), e);
|
|
||||||
}
|
}
|
||||||
// delete original OVA file
|
if (LOGGER.isTraceEnabled()) {
|
||||||
// templateFile.delete();
|
LOGGER.trace("We are handling format " + format + ".");
|
||||||
return info;
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -128,34 +203,43 @@ public class OVAProcessor extends AdapterBase implements Processor {
|
|||||||
long size = getTemplateVirtualSize(file.getParent(), file.getName());
|
long size = getTemplateVirtualSize(file.getParent(), file.getName());
|
||||||
return size;
|
return size;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
s_logger.info("[ignored]"
|
LOGGER.info("[ignored]"
|
||||||
+ "failed to get virtual template size for ova: " + e.getLocalizedMessage());
|
+ "failed to get virtual template size for ova: " + e.getLocalizedMessage());
|
||||||
}
|
}
|
||||||
return file.length();
|
return file.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets the virtual size from the OVF file meta data.
|
||||||
|
*
|
||||||
|
* @return the accumulative virtual size of the disk definitions in the OVF
|
||||||
|
* @throws InternalErrorException
|
||||||
|
*/
|
||||||
public long getTemplateVirtualSize(String templatePath, String templateName) throws InternalErrorException {
|
public long getTemplateVirtualSize(String templatePath, String templateName) throws InternalErrorException {
|
||||||
// get the virtual size from the OVF file meta data
|
|
||||||
long virtualSize = 0;
|
long virtualSize = 0;
|
||||||
String templateFileFullPath = templatePath.endsWith(File.separator) ? templatePath : templatePath + File.separator;
|
String templateFileFullPath = templatePath.endsWith(File.separator) ? templatePath : templatePath + File.separator;
|
||||||
templateFileFullPath += templateName.endsWith(ImageFormat.OVA.getFileExtension()) ? templateName : templateName + "." + ImageFormat.OVA.getFileExtension();
|
templateFileFullPath += templateName.endsWith(ImageFormat.OVA.getFileExtension()) ? templateName : templateName + "." + ImageFormat.OVA.getFileExtension();
|
||||||
String ovfFileName = getOVFFilePath(templateFileFullPath);
|
String ovfFileName = getOVFFilePath(templateFileFullPath);
|
||||||
if (ovfFileName == null) {
|
if (ovfFileName == null) {
|
||||||
String msg = "Unable to locate OVF file in template package directory: " + templatePath;
|
String msg = "Unable to locate OVF file in template package directory: " + templatePath;
|
||||||
s_logger.error(msg);
|
LOGGER.error(msg);
|
||||||
throw new InternalErrorException(msg);
|
throw new InternalErrorException(msg);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Document ovfDoc = null;
|
Document ovfDoc = null;
|
||||||
ovfDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File(ovfFileName));
|
ovfDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File(ovfFileName));
|
||||||
Element disk = (Element)ovfDoc.getElementsByTagName("Disk").item(0);
|
NodeList diskElements = ovfDoc.getElementsByTagName("Disk");
|
||||||
virtualSize = Long.parseLong(disk.getAttribute("ovf:capacity"));
|
for (int i = 0; i < diskElements.getLength(); i++) {
|
||||||
|
Element disk = (Element)diskElements.item(i);
|
||||||
|
long diskSize = Long.parseLong(disk.getAttribute("ovf:capacity"));
|
||||||
String allocationUnits = disk.getAttribute("ovf:capacityAllocationUnits");
|
String allocationUnits = disk.getAttribute("ovf:capacityAllocationUnits");
|
||||||
virtualSize = OVFHelper.getDiskVirtualSize(virtualSize, allocationUnits, ovfFileName);
|
diskSize = OVFHelper.getDiskVirtualSize(diskSize, allocationUnits, ovfFileName);
|
||||||
|
virtualSize += diskSize;
|
||||||
|
}
|
||||||
return virtualSize;
|
return virtualSize;
|
||||||
} catch (Exception e) {
|
} catch (InternalErrorException | IOException | NumberFormatException | ParserConfigurationException | SAXException e) {
|
||||||
String msg = "getTemplateVirtualSize: Unable to parse OVF XML document " + templatePath + " to get the virtual disk " + templateName + " size due to " + e;
|
String msg = "getTemplateVirtualSize: Unable to parse OVF XML document " + templatePath + " to get the virtual disk " + templateName + " size due to " + e;
|
||||||
s_logger.error(msg);
|
LOGGER.error(msg);
|
||||||
throw new InternalErrorException(msg);
|
throw new InternalErrorException(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -187,9 +271,9 @@ public class OVAProcessor extends AdapterBase implements Processor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new Pair<Long, Long>(virtualSize, fileSize);
|
return new Pair<Long, Long>(virtualSize, fileSize);
|
||||||
} catch (Exception e) {
|
} catch (InternalErrorException | IOException | NumberFormatException | ParserConfigurationException | SAXException e) {
|
||||||
String msg = "getDiskDetails: Unable to parse OVF XML document " + ovfFilePath + " to get the virtual disk " + diskName + " size due to " + e;
|
String msg = "getDiskDetails: Unable to parse OVF XML document " + ovfFilePath + " to get the virtual disk " + diskName + " size due to " + e;
|
||||||
s_logger.error(msg);
|
LOGGER.error(msg);
|
||||||
throw new InternalErrorException(msg);
|
throw new InternalErrorException(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,10 +23,14 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.storage.OVFEulaSectionTO;
|
||||||
import com.cloud.agent.api.storage.OVFPropertyTO;
|
import com.cloud.agent.api.storage.OVFPropertyTO;
|
||||||
|
import com.cloud.agent.api.storage.OVFVirtualHardwareSectionTO;
|
||||||
|
import com.cloud.agent.api.to.DatadiskTO;
|
||||||
import com.cloud.exception.InternalErrorException;
|
import com.cloud.exception.InternalErrorException;
|
||||||
import com.cloud.storage.Storage.ImageFormat;
|
import com.cloud.storage.Storage.ImageFormat;
|
||||||
import com.cloud.utils.component.Adapter;
|
import com.cloud.utils.component.Adapter;
|
||||||
|
import org.apache.cloudstack.api.net.NetworkPrerequisiteTO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic interface to process different types of image formats
|
* Generic interface to process different types of image formats
|
||||||
@ -48,13 +52,17 @@ public interface Processor extends Adapter {
|
|||||||
|
|
||||||
FormatInfo process(String templatePath, ImageFormat format, String templateName, long processTimeout) throws InternalErrorException;
|
FormatInfo process(String templatePath, ImageFormat format, String templateName, long processTimeout) throws InternalErrorException;
|
||||||
|
|
||||||
public static class FormatInfo {
|
class FormatInfo {
|
||||||
public ImageFormat format;
|
public ImageFormat format;
|
||||||
public long size;
|
public long size;
|
||||||
public long virtualSize;
|
public long virtualSize;
|
||||||
public String filename;
|
public String filename;
|
||||||
public boolean isCorrupted;
|
public boolean isCorrupted;
|
||||||
public List<OVFPropertyTO> ovfProperties;
|
public List<OVFPropertyTO> ovfProperties;
|
||||||
|
public List<NetworkPrerequisiteTO> networks;
|
||||||
|
public List<DatadiskTO> disks;
|
||||||
|
public OVFVirtualHardwareSectionTO hardwareSection;
|
||||||
|
public List<OVFEulaSectionTO> eulaSections;
|
||||||
}
|
}
|
||||||
|
|
||||||
long getVirtualSize(File file) throws IOException;
|
long getVirtualSize(File file) throws IOException;
|
||||||
|
|||||||
@ -47,6 +47,8 @@ public class TemplateObjectTO implements DataTO {
|
|||||||
private boolean bootable;
|
private boolean bootable;
|
||||||
private String uniqueName;
|
private String uniqueName;
|
||||||
private boolean directDownload;
|
private boolean directDownload;
|
||||||
|
private boolean deployAsIs;
|
||||||
|
private String deployAsIsConfiguration;
|
||||||
|
|
||||||
public TemplateObjectTO() {
|
public TemplateObjectTO() {
|
||||||
|
|
||||||
@ -82,6 +84,8 @@ public class TemplateObjectTO implements DataTO {
|
|||||||
this.imageDataStore = template.getDataStore().getTO();
|
this.imageDataStore = template.getDataStore().getTO();
|
||||||
}
|
}
|
||||||
this.hypervisorType = template.getHypervisorType();
|
this.hypervisorType = template.getHypervisorType();
|
||||||
|
this.deployAsIs = template.isDeployAsIs();
|
||||||
|
this.deployAsIsConfiguration = template.getDeployAsIsConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -244,6 +248,18 @@ public class TemplateObjectTO implements DataTO {
|
|||||||
this.directDownload = directDownload;
|
this.directDownload = directDownload;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isDeployAsIs() {
|
||||||
|
return deployAsIs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeployAsIsConfiguration() {
|
||||||
|
return deployAsIsConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeployAsIsConfiguration(String deployAsIsConfiguration) {
|
||||||
|
this.deployAsIsConfiguration = deployAsIsConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return new StringBuilder("TemplateTO[id=").append(id).append("|origUrl=").append(origUrl).append("|name").append(name).append("]").toString();
|
return new StringBuilder("TemplateTO[id=").append(id).append("|origUrl=").append(origUrl).append("|name").append(name).append("]").toString();
|
||||||
|
|||||||
@ -0,0 +1,58 @@
|
|||||||
|
// 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 com.cloud.agent.api.Answer;
|
||||||
|
import com.cloud.serializer.GsonHelper;
|
||||||
|
import com.cloud.storage.VMTemplateStorageResourceAssoc;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import org.apache.cloudstack.api.net.NetworkPrerequisiteTO;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class DownloadAnswerTest {
|
||||||
|
Gson gson = GsonHelper.getGson();
|
||||||
|
|
||||||
|
VMTemplateStorageResourceAssoc.Status status = VMTemplateStorageResourceAssoc.Status.DOWNLOADED;
|
||||||
|
DownloadAnswer answer = new DownloadAnswer("nothin wrong", status);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void redeserialise ()
|
||||||
|
{
|
||||||
|
String json = gson.toJson(answer);
|
||||||
|
DownloadAnswer received = gson.fromJson(json, DownloadAnswer.class);
|
||||||
|
Assert.assertEquals(received,answer);
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void properties ()
|
||||||
|
{
|
||||||
|
List<OVFPropertyTO> properties = new ArrayList<>();
|
||||||
|
properties.add(new OVFPropertyTO());
|
||||||
|
List<NetworkPrerequisiteTO> networks = new ArrayList<>();
|
||||||
|
networks.add(new NetworkPrerequisiteTO());
|
||||||
|
|
||||||
|
answer.setOvfProperties(properties);
|
||||||
|
answer.setNetworkRequirements(networks);
|
||||||
|
|
||||||
|
String json = gson.toJson(answer);
|
||||||
|
Answer received = gson.fromJson(json, Answer.class);
|
||||||
|
Assert.assertEquals(received,answer);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.cloudstack.engine.orchestration.service;
|
package org.apache.cloudstack.engine.orchestration.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@ -119,7 +120,10 @@ public interface VolumeOrchestrationService {
|
|||||||
|
|
||||||
boolean canVmRestartOnAnotherServer(long vmId);
|
boolean canVmRestartOnAnotherServer(long vmId);
|
||||||
|
|
||||||
DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering offering, Long rootDisksize, Long minIops, Long maxIops, VirtualMachineTemplate template, VirtualMachine vm,
|
/**
|
||||||
|
* Allocate a volume or multiple volumes in case of template is registered with the 'deploy-as-is' option, allowing multiple disks
|
||||||
|
*/
|
||||||
|
List<DiskProfile> allocateTemplatedVolumes(Type type, String name, DiskOffering offering, Long rootDisksize, Long minIops, Long maxIops, VirtualMachineTemplate template, VirtualMachine vm,
|
||||||
Account owner);
|
Account owner);
|
||||||
|
|
||||||
String getVmNameFromVolumeId(long volumeId);
|
String getVmNameFromVolumeId(long volumeId);
|
||||||
|
|||||||
@ -55,7 +55,7 @@ public interface OrchestrationService {
|
|||||||
* @param memory memory to allocate in bytes
|
* @param memory memory to allocate in bytes
|
||||||
* @param computeTags tags for the compute
|
* @param computeTags tags for the compute
|
||||||
* @param rootDiskTags tags for the root disk
|
* @param rootDiskTags tags for the root disk
|
||||||
* @param networks networks that this VM should join
|
* @param networkNicMap map networks to nic profiles that this VM should join
|
||||||
* @param rootDiskSize size the root disk in case of templates.
|
* @param rootDiskSize size the root disk in case of templates.
|
||||||
* @return VirtualMachineEntity
|
* @return VirtualMachineEntity
|
||||||
*/
|
*/
|
||||||
@ -65,7 +65,7 @@ public interface OrchestrationService {
|
|||||||
@QueryParam("host-name") String hostName, @QueryParam("display-name") String displayName, @QueryParam("hypervisor") String hypervisor,
|
@QueryParam("host-name") String hostName, @QueryParam("display-name") String displayName, @QueryParam("hypervisor") String hypervisor,
|
||||||
@QueryParam("cpu") int cpu, @QueryParam("speed") int speed, @QueryParam("ram") long memory, @QueryParam("disk-size") Long diskSize,
|
@QueryParam("cpu") int cpu, @QueryParam("speed") int speed, @QueryParam("ram") long memory, @QueryParam("disk-size") Long diskSize,
|
||||||
@QueryParam("compute-tags") List<String> computeTags, @QueryParam("root-disk-tags") List<String> rootDiskTags,
|
@QueryParam("compute-tags") List<String> computeTags, @QueryParam("root-disk-tags") List<String> rootDiskTags,
|
||||||
@QueryParam("network-nic-map") Map<String, NicProfile> networkNicMap, @QueryParam("deploymentplan") DeploymentPlan plan,
|
@QueryParam("network-nic-map") Map<String, List<NicProfile>> networkNicMap, @QueryParam("deploymentplan") DeploymentPlan plan,
|
||||||
@QueryParam("root-disk-size") Long rootDiskSize, @QueryParam("extra-dhcp-option-map") Map<String, Map<Integer, String>> extraDhcpOptionMap,
|
@QueryParam("root-disk-size") Long rootDiskSize, @QueryParam("extra-dhcp-option-map") Map<String, Map<Integer, String>> extraDhcpOptionMap,
|
||||||
@QueryParam("datadisktemplate-diskoffering-map") Map<Long, DiskOffering> datadiskTemplateToDiskOfferingMap) throws InsufficientCapacityException;
|
@QueryParam("datadisktemplate-diskoffering-map") Map<Long, DiskOffering> datadiskTemplateToDiskOfferingMap) throws InsufficientCapacityException;
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ public interface OrchestrationService {
|
|||||||
@QueryParam("host-name") String hostName, @QueryParam("display-name") String displayName, @QueryParam("hypervisor") String hypervisor,
|
@QueryParam("host-name") String hostName, @QueryParam("display-name") String displayName, @QueryParam("hypervisor") String hypervisor,
|
||||||
@QueryParam("os") String os, @QueryParam("cpu") int cpu, @QueryParam("speed") int speed, @QueryParam("ram") long memory, @QueryParam("disk-size") Long diskSize,
|
@QueryParam("os") String os, @QueryParam("cpu") int cpu, @QueryParam("speed") int speed, @QueryParam("ram") long memory, @QueryParam("disk-size") Long diskSize,
|
||||||
@QueryParam("compute-tags") List<String> computeTags, @QueryParam("root-disk-tags") List<String> rootDiskTags,
|
@QueryParam("compute-tags") List<String> computeTags, @QueryParam("root-disk-tags") List<String> rootDiskTags,
|
||||||
@QueryParam("network-nic-map") Map<String, NicProfile> networkNicMap, @QueryParam("deploymentplan") DeploymentPlan plan, @QueryParam("extra-dhcp-option-map") Map<String, Map<Integer, String>> extraDhcpOptionMap) throws InsufficientCapacityException;
|
@QueryParam("network-nic-map") Map<String, List<NicProfile>> networkNicMap, @QueryParam("deploymentplan") DeploymentPlan plan, @QueryParam("extra-dhcp-option-map") Map<String, Map<Integer, String>> extraDhcpOptionMap) throws InsufficientCapacityException;
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
NetworkEntity createNetwork(String id, String name, String domainName, String cidr, String gateway);
|
NetworkEntity createNetwork(String id, String name, String domainName, String cidr, String gateway);
|
||||||
|
|||||||
@ -23,7 +23,9 @@ import java.util.List;
|
|||||||
import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat;
|
import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat;
|
||||||
|
|
||||||
public interface PrimaryDataStore extends DataStore, PrimaryDataStoreInfo {
|
public interface PrimaryDataStore extends DataStore, PrimaryDataStoreInfo {
|
||||||
DataObject create(DataObject dataObject, boolean createEntryInTempSpoolRef);
|
DataObject create(DataObject dataObject, String configuration);
|
||||||
|
|
||||||
|
DataObject create(DataObject dataObject, boolean createEntryInTempSpoolRef, String configuration);
|
||||||
|
|
||||||
VolumeInfo getVolume(long id);
|
VolumeInfo getVolume(long id);
|
||||||
|
|
||||||
@ -31,7 +33,7 @@ public interface PrimaryDataStore extends DataStore, PrimaryDataStoreInfo {
|
|||||||
|
|
||||||
boolean exists(DataObject data);
|
boolean exists(DataObject data);
|
||||||
|
|
||||||
TemplateInfo getTemplate(long templateId);
|
TemplateInfo getTemplate(long templateId, String configuration);
|
||||||
|
|
||||||
SnapshotInfo getSnapshot(long snapshotId);
|
SnapshotInfo getSnapshot(long snapshotId);
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,7 @@ public interface TemplateDataFactory {
|
|||||||
|
|
||||||
TemplateInfo getReadyTemplateOnImageStore(long templateId, Long zoneId);
|
TemplateInfo getReadyTemplateOnImageStore(long templateId, Long zoneId);
|
||||||
|
|
||||||
TemplateInfo getTemplate(DataObject obj, DataStore store);
|
TemplateInfo getTemplate(DataObject obj, DataStore store, String configuration);
|
||||||
|
|
||||||
TemplateInfo getTemplate(long templateId, DataStoreRole storeRole);
|
TemplateInfo getTemplate(long templateId, DataStoreRole storeRole);
|
||||||
|
|
||||||
@ -40,4 +40,6 @@ public interface TemplateDataFactory {
|
|||||||
TemplateInfo getReadyBypassedTemplateOnPrimaryStore(long templateId, Long poolId, Long hostId);
|
TemplateInfo getReadyBypassedTemplateOnPrimaryStore(long templateId, Long poolId, Long hostId);
|
||||||
|
|
||||||
boolean isTemplateMarkedForDirectDownload(long templateId);
|
boolean isTemplateMarkedForDirectDownload(long templateId);
|
||||||
|
|
||||||
|
TemplateInfo getTemplateOnPrimaryStorage(long templateId, DataStore store, String configuration);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,4 +27,8 @@ public interface TemplateInfo extends DataObject, VirtualMachineTemplate {
|
|||||||
String getInstallPath();
|
String getInstallPath();
|
||||||
|
|
||||||
boolean isDirectDownload();
|
boolean isDirectDownload();
|
||||||
|
|
||||||
|
boolean isDeployAsIs();
|
||||||
|
|
||||||
|
String getDeployAsIsConfiguration();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.cloudstack.engine.subsystem.api.storage;
|
package org.apache.cloudstack.engine.subsystem.api.storage;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.to.DatadiskTO;
|
||||||
import org.apache.cloudstack.framework.async.AsyncCallFuture;
|
import org.apache.cloudstack.framework.async.AsyncCallFuture;
|
||||||
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
|
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
|
||||||
import org.apache.cloudstack.storage.command.CommandResult;
|
import org.apache.cloudstack.storage.command.CommandResult;
|
||||||
@ -25,6 +26,8 @@ import org.apache.cloudstack.storage.command.CommandResult;
|
|||||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||||
import com.cloud.storage.StoragePool;
|
import com.cloud.storage.StoragePool;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public interface TemplateService {
|
public interface TemplateService {
|
||||||
|
|
||||||
class TemplateApiResult extends CommandResult {
|
class TemplateApiResult extends CommandResult {
|
||||||
@ -47,7 +50,7 @@ public interface TemplateService {
|
|||||||
|
|
||||||
AsyncCallFuture<TemplateApiResult> createTemplateFromVolumeAsync(VolumeInfo volume, TemplateInfo template, DataStore store);
|
AsyncCallFuture<TemplateApiResult> createTemplateFromVolumeAsync(VolumeInfo volume, TemplateInfo template, DataStore store);
|
||||||
|
|
||||||
boolean createOvaDataDiskTemplates(TemplateInfo parentTemplate);
|
boolean createOvaDataDiskTemplates(TemplateInfo parentTemplate, boolean deployAsIs);
|
||||||
|
|
||||||
AsyncCallFuture<TemplateApiResult> deleteTemplateAsync(TemplateInfo template);
|
AsyncCallFuture<TemplateApiResult> deleteTemplateAsync(TemplateInfo template);
|
||||||
|
|
||||||
@ -72,4 +75,6 @@ public interface TemplateService {
|
|||||||
void associateCrosszoneTemplatesToZone(long dcId);
|
void associateCrosszoneTemplatesToZone(long dcId);
|
||||||
|
|
||||||
AsyncCallFuture<TemplateApiResult> createDatadiskTemplateAsync(TemplateInfo parentTemplate, TemplateInfo dataDiskTemplate, String path, String diskId, long fileSize, boolean bootable);
|
AsyncCallFuture<TemplateApiResult> createDatadiskTemplateAsync(TemplateInfo parentTemplate, TemplateInfo dataDiskTemplate, String path, String diskId, long fileSize, boolean bootable);
|
||||||
|
|
||||||
|
List<DatadiskTO> getTemplateDatadisksOnImageStore(TemplateInfo templateInfo, String configurationId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -83,4 +83,8 @@ public interface VolumeInfo extends DataObject, Volume {
|
|||||||
boolean isDirectDownload();
|
boolean isDirectDownload();
|
||||||
|
|
||||||
void setDirectDownload(boolean directDownload);
|
void setDirectDownload(boolean directDownload);
|
||||||
|
|
||||||
|
boolean isDeployAsIs();
|
||||||
|
|
||||||
|
String getDeployAsIsConfiguration();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,7 +51,7 @@ public interface ImageStoreEntity extends DataStore, ImageStore {
|
|||||||
|
|
||||||
void deleteExtractUrl(String installPath, String url, Upload.Type volume);
|
void deleteExtractUrl(String installPath, String url, Upload.Type volume);
|
||||||
|
|
||||||
List<DatadiskTO> getDataDiskTemplates(DataObject obj);
|
List<DatadiskTO> getDataDiskTemplates(DataObject obj, String configurationId);
|
||||||
|
|
||||||
Void createDataDiskTemplateAsync(TemplateInfo dataDiskTemplate, String path, String diskId, long fileSize, boolean bootable, AsyncCompletionCallback<CreateCmdResult> callback);
|
Void createDataDiskTemplateAsync(TemplateInfo dataDiskTemplate, String path, String diskId, long fileSize, boolean bootable, AsyncCompletionCallback<CreateCmdResult> callback);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,9 @@ package com.cloud.template;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.to.DatadiskTO;
|
||||||
import com.cloud.deploy.DeployDestination;
|
import com.cloud.deploy.DeployDestination;
|
||||||
|
import com.cloud.storage.DataStoreRole;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
|
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
|
||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
@ -133,4 +135,5 @@ public interface TemplateManager {
|
|||||||
public static final String MESSAGE_REGISTER_PUBLIC_TEMPLATE_EVENT = "Message.RegisterPublicTemplate.Event";
|
public static final String MESSAGE_REGISTER_PUBLIC_TEMPLATE_EVENT = "Message.RegisterPublicTemplate.Event";
|
||||||
public static final String MESSAGE_RESET_TEMPLATE_PERMISSION_EVENT = "Message.ResetTemplatePermission.Event";
|
public static final String MESSAGE_RESET_TEMPLATE_PERMISSION_EVENT = "Message.ResetTemplatePermission.Event";
|
||||||
|
|
||||||
|
List<DatadiskTO> getTemplateDisksOnImageStore(Long templateId, DataStoreRole role, String configurationId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -414,6 +414,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
final LinkedHashMap<? extends Network, List<? extends NicProfile>> auxiliaryNetworks, final DeploymentPlan plan, final HypervisorType hyperType, final Map<String, Map<Integer, String>> extraDhcpOptions, final Map<Long, DiskOffering> datadiskTemplateToDiskOfferingMap)
|
final LinkedHashMap<? extends Network, List<? extends NicProfile>> auxiliaryNetworks, final DeploymentPlan plan, final HypervisorType hyperType, final Map<String, Map<Integer, String>> extraDhcpOptions, final Map<Long, DiskOffering> datadiskTemplateToDiskOfferingMap)
|
||||||
throws InsufficientCapacityException {
|
throws InsufficientCapacityException {
|
||||||
|
|
||||||
|
s_logger.info(String.format("allocating virtual machine from template:%s with hostname:%s and %d networks", template.getUuid(), vmInstanceName, auxiliaryNetworks.size()));
|
||||||
|
|
||||||
final VMInstanceVO vm = _vmDao.findVMByInstanceName(vmInstanceName);
|
final VMInstanceVO vm = _vmDao.findVMByInstanceName(vmInstanceName);
|
||||||
final Account owner = _entityMgr.findById(Account.class, vm.getAccountId());
|
final Account owner = _entityMgr.findById(Account.class, vm.getAccountId());
|
||||||
|
|
||||||
@ -455,7 +457,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
} else if (template.getFormat() == ImageFormat.BAREMETAL) {
|
} else if (template.getFormat() == ImageFormat.BAREMETAL) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
} else {
|
} else {
|
||||||
volumeMgr.allocateTemplatedVolume(Type.ROOT, "ROOT-" + vmFinal.getId(), rootDiskOfferingInfo.getDiskOffering(), rootDiskOfferingInfo.getSize(),
|
volumeMgr.allocateTemplatedVolumes(Type.ROOT, "ROOT-" + vmFinal.getId(), rootDiskOfferingInfo.getDiskOffering(), rootDiskOfferingInfo.getSize(),
|
||||||
rootDiskOfferingInfo.getMinIops(), rootDiskOfferingInfo.getMaxIops(), template, vmFinal, owner);
|
rootDiskOfferingInfo.getMinIops(), rootDiskOfferingInfo.getMaxIops(), template, vmFinal, owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1104,8 +1106,10 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
|
|
||||||
if (dest != null) {
|
if (dest != null) {
|
||||||
avoids.addHost(dest.getHost().getId());
|
avoids.addHost(dest.getHost().getId());
|
||||||
|
if (!template.isDeployAsIs()) {
|
||||||
journal.record("Deployment found ", vmProfile, dest);
|
journal.record("Deployment found ", vmProfile, dest);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
long destHostId = dest.getHost().getId();
|
long destHostId = dest.getHost().getId();
|
||||||
vm.setPodIdToDeployIn(dest.getPod().getId());
|
vm.setPodIdToDeployIn(dest.getPod().getId());
|
||||||
@ -1468,6 +1472,11 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
if (disk.getType() != Volume.Type.ISO) {
|
if (disk.getType() != Volume.Type.ISO) {
|
||||||
final VolumeObjectTO vol = (VolumeObjectTO)disk.getData();
|
final VolumeObjectTO vol = (VolumeObjectTO)disk.getData();
|
||||||
final VolumeVO volume = _volsDao.findById(vol.getId());
|
final VolumeVO volume = _volsDao.findById(vol.getId());
|
||||||
|
if (vmSpec.getDeployAsIsInfo() != null && vmSpec.getDeployAsIsInfo().isDeployAsIs()
|
||||||
|
&& StringUtils.isNotBlank(vol.getPath())) {
|
||||||
|
volume.setPath(vol.getPath());
|
||||||
|
_volsDao.update(volume.getId(), volume);
|
||||||
|
}
|
||||||
|
|
||||||
// Use getPath() from VolumeVO to get a fresh copy of what's in the DB.
|
// Use getPath() from VolumeVO to get a fresh copy of what's in the DB.
|
||||||
// Before doing this, in a certain situation, getPath() from VolumeObjectTO
|
// Before doing this, in a certain situation, getPath() from VolumeObjectTO
|
||||||
|
|||||||
@ -20,7 +20,6 @@ package org.apache.cloudstack.engine.orchestration;
|
|||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -156,7 +155,7 @@ public class CloudOrchestrator implements OrchestrationService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VirtualMachineEntity createVirtualMachine(String id, String owner, String templateId, String hostName, String displayName, String hypervisor, int cpu,
|
public VirtualMachineEntity createVirtualMachine(String id, String owner, String templateId, String hostName, String displayName, String hypervisor, int cpu,
|
||||||
int speed, long memory, Long diskSize, List<String> computeTags, List<String> rootDiskTags, Map<String, NicProfile> networkNicMap, DeploymentPlan plan,
|
int speed, long memory, Long diskSize, List<String> computeTags, List<String> rootDiskTags, Map<String, List<NicProfile>> networkNicMap, DeploymentPlan plan,
|
||||||
Long rootDiskSize, Map<String, Map<Integer, String>> extraDhcpOptionMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap) throws InsufficientCapacityException {
|
Long rootDiskSize, Map<String, Map<Integer, String>> extraDhcpOptionMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap) throws InsufficientCapacityException {
|
||||||
|
|
||||||
// VirtualMachineEntityImpl vmEntity = new VirtualMachineEntityImpl(id, owner, hostName, displayName, cpu, speed, memory, computeTags, rootDiskTags, networks,
|
// VirtualMachineEntityImpl vmEntity = new VirtualMachineEntityImpl(id, owner, hostName, displayName, cpu, speed, memory, computeTags, rootDiskTags, networks,
|
||||||
@ -166,7 +165,7 @@ public class CloudOrchestrator implements OrchestrationService {
|
|||||||
for (String uuid : networkNicMap.keySet()) {
|
for (String uuid : networkNicMap.keySet()) {
|
||||||
NetworkVO network = _networkDao.findByUuid(uuid);
|
NetworkVO network = _networkDao.findByUuid(uuid);
|
||||||
if(network != null){
|
if(network != null){
|
||||||
networkIpMap.put(network, new ArrayList<NicProfile>(Arrays.asList(networkNicMap.get(uuid))));
|
networkIpMap.put(network, networkNicMap.get(uuid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,7 +254,7 @@ public class CloudOrchestrator implements OrchestrationService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VirtualMachineEntity createVirtualMachineFromScratch(String id, String owner, String isoId, String hostName, String displayName, String hypervisor, String os,
|
public VirtualMachineEntity createVirtualMachineFromScratch(String id, String owner, String isoId, String hostName, String displayName, String hypervisor, String os,
|
||||||
int cpu, int speed, long memory, Long diskSize, List<String> computeTags, List<String> rootDiskTags, Map<String, NicProfile> networkNicMap, DeploymentPlan plan, Map<String, Map<Integer, String>> extraDhcpOptionMap)
|
int cpu, int speed, long memory, Long diskSize, List<String> computeTags, List<String> rootDiskTags, Map<String, List<NicProfile>> networkNicMap, DeploymentPlan plan, Map<String, Map<Integer, String>> extraDhcpOptionMap)
|
||||||
throws InsufficientCapacityException {
|
throws InsufficientCapacityException {
|
||||||
|
|
||||||
// VirtualMachineEntityImpl vmEntity = new VirtualMachineEntityImpl(id, owner, hostName, displayName, cpu, speed, memory, computeTags, rootDiskTags, networks, vmEntityManager);
|
// VirtualMachineEntityImpl vmEntity = new VirtualMachineEntityImpl(id, owner, hostName, displayName, cpu, speed, memory, computeTags, rootDiskTags, networks, vmEntityManager);
|
||||||
@ -307,7 +306,7 @@ public class CloudOrchestrator implements OrchestrationService {
|
|||||||
for (String uuid : networkNicMap.keySet()) {
|
for (String uuid : networkNicMap.keySet()) {
|
||||||
NetworkVO network = _networkDao.findByUuid(uuid);
|
NetworkVO network = _networkDao.findByUuid(uuid);
|
||||||
if(network != null){
|
if(network != null){
|
||||||
networkIpMap.put(network, new ArrayList<NicProfile>(Arrays.asList(networkNicMap.get(uuid))));
|
networkIpMap.put(network, networkNicMap.get(uuid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,8 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package org.apache.cloudstack.engine.orchestration;
|
package org.apache.cloudstack.engine.orchestration;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang.StringUtils.isNotBlank;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -38,12 +40,9 @@ import java.util.stream.Collectors;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
import com.cloud.event.EventTypes;
|
|
||||||
import com.cloud.event.UsageEventUtils;
|
|
||||||
import com.cloud.network.dao.NetworkDetailVO;
|
|
||||||
import com.cloud.network.dao.NetworkDetailsDao;
|
|
||||||
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
|
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
|
||||||
import org.apache.cloudstack.api.ApiConstants;
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
import org.apache.cloudstack.api.net.NetworkPrerequisiteTO;
|
||||||
import org.apache.cloudstack.context.CallContext;
|
import org.apache.cloudstack.context.CallContext;
|
||||||
import org.apache.cloudstack.engine.cloud.entity.api.db.VMNetworkMapVO;
|
import org.apache.cloudstack.engine.cloud.entity.api.db.VMNetworkMapVO;
|
||||||
import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMNetworkMapDao;
|
import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMNetworkMapDao;
|
||||||
@ -88,6 +87,8 @@ import com.cloud.deploy.DataCenterDeployment;
|
|||||||
import com.cloud.deploy.DeployDestination;
|
import com.cloud.deploy.DeployDestination;
|
||||||
import com.cloud.deploy.DeploymentPlan;
|
import com.cloud.deploy.DeploymentPlan;
|
||||||
import com.cloud.domain.Domain;
|
import com.cloud.domain.Domain;
|
||||||
|
import com.cloud.event.EventTypes;
|
||||||
|
import com.cloud.event.UsageEventUtils;
|
||||||
import com.cloud.exception.ConcurrentOperationException;
|
import com.cloud.exception.ConcurrentOperationException;
|
||||||
import com.cloud.exception.ConnectionException;
|
import com.cloud.exception.ConnectionException;
|
||||||
import com.cloud.exception.InsufficientAddressCapacityException;
|
import com.cloud.exception.InsufficientAddressCapacityException;
|
||||||
@ -129,6 +130,8 @@ import com.cloud.network.dao.IPAddressVO;
|
|||||||
import com.cloud.network.dao.NetworkAccountDao;
|
import com.cloud.network.dao.NetworkAccountDao;
|
||||||
import com.cloud.network.dao.NetworkAccountVO;
|
import com.cloud.network.dao.NetworkAccountVO;
|
||||||
import com.cloud.network.dao.NetworkDao;
|
import com.cloud.network.dao.NetworkDao;
|
||||||
|
import com.cloud.network.dao.NetworkDetailVO;
|
||||||
|
import com.cloud.network.dao.NetworkDetailsDao;
|
||||||
import com.cloud.network.dao.NetworkDomainDao;
|
import com.cloud.network.dao.NetworkDomainDao;
|
||||||
import com.cloud.network.dao.NetworkDomainVO;
|
import com.cloud.network.dao.NetworkDomainVO;
|
||||||
import com.cloud.network.dao.NetworkServiceMapDao;
|
import com.cloud.network.dao.NetworkServiceMapDao;
|
||||||
@ -178,6 +181,7 @@ import com.cloud.offerings.NetworkOfferingVO;
|
|||||||
import com.cloud.offerings.dao.NetworkOfferingDao;
|
import com.cloud.offerings.dao.NetworkOfferingDao;
|
||||||
import com.cloud.offerings.dao.NetworkOfferingDetailsDao;
|
import com.cloud.offerings.dao.NetworkOfferingDetailsDao;
|
||||||
import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
|
import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
|
||||||
|
import com.cloud.storage.dao.VMTemplateDetailsDao;
|
||||||
import com.cloud.user.Account;
|
import com.cloud.user.Account;
|
||||||
import com.cloud.user.ResourceLimitService;
|
import com.cloud.user.ResourceLimitService;
|
||||||
import com.cloud.user.User;
|
import com.cloud.user.User;
|
||||||
@ -231,8 +235,6 @@ import com.cloud.vm.dao.UserVmDao;
|
|||||||
import com.cloud.vm.dao.VMInstanceDao;
|
import com.cloud.vm.dao.VMInstanceDao;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
|
|
||||||
import static org.apache.commons.lang.StringUtils.isNotBlank;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NetworkManagerImpl implements NetworkManager.
|
* NetworkManagerImpl implements NetworkManager.
|
||||||
*/
|
*/
|
||||||
@ -301,6 +303,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||||||
VpcVirtualNetworkApplianceService _routerService;
|
VpcVirtualNetworkApplianceService _routerService;
|
||||||
@Inject
|
@Inject
|
||||||
UserVmManager _userVmMgr;
|
UserVmManager _userVmMgr;
|
||||||
|
@Inject
|
||||||
|
VMTemplateDetailsDao templateDetailsDao;
|
||||||
|
|
||||||
List<NetworkGuru> networkGurus;
|
List<NetworkGuru> networkGurus;
|
||||||
|
|
||||||
@ -752,34 +756,39 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||||||
Transaction.execute(new TransactionCallbackWithExceptionNoReturn<InsufficientCapacityException>() {
|
Transaction.execute(new TransactionCallbackWithExceptionNoReturn<InsufficientCapacityException>() {
|
||||||
@Override
|
@Override
|
||||||
public void doInTransactionWithoutResult(final TransactionStatus status) throws InsufficientCapacityException {
|
public void doInTransactionWithoutResult(final TransactionStatus status) throws InsufficientCapacityException {
|
||||||
|
if (s_logger.isTraceEnabled()) {
|
||||||
|
s_logger.trace(String.format("allocating networks for %s(template %s); %d networks",vm.getInstanceName(), vm.getTemplate().getUuid(), networks.size()));
|
||||||
|
}
|
||||||
int deviceId = 0;
|
int deviceId = 0;
|
||||||
int size = 0;
|
int size;
|
||||||
for (final Network ntwk : networks.keySet()) {
|
size = determineNumberOfNicsRequired();
|
||||||
final List<? extends NicProfile> profiles = networks.get(ntwk);
|
|
||||||
if (profiles != null && !profiles.isEmpty()) {
|
|
||||||
size = size + profiles.size();
|
|
||||||
} else {
|
|
||||||
size = size + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final boolean[] deviceIds = new boolean[size];
|
final boolean[] deviceIds = new boolean[size];
|
||||||
Arrays.fill(deviceIds, false);
|
Arrays.fill(deviceIds, false);
|
||||||
|
|
||||||
|
List<Pair<Network, NicProfile>> profilesList = getOrderedNetworkNicProfileMapping(networks);
|
||||||
final List<NicProfile> nics = new ArrayList<NicProfile>(size);
|
final List<NicProfile> nics = new ArrayList<NicProfile>(size);
|
||||||
NicProfile defaultNic = null;
|
NicProfile defaultNic = null;
|
||||||
|
Network nextNetwork = null;
|
||||||
for (final Map.Entry<? extends Network, List<? extends NicProfile>> network : networks.entrySet()) {
|
for (Pair <Network, NicProfile> networkNicPair : profilesList) {
|
||||||
final Network config = network.getKey();
|
nextNetwork = networkNicPair.first();
|
||||||
List<? extends NicProfile> requestedProfiles = network.getValue();
|
Pair<NicProfile, Integer> newDeviceInfo = addRequestedNicToNicListWithDeviceNumberAndRetrieveDefaultDevice(networkNicPair.second(), deviceIds, deviceId, nextNetwork, nics, defaultNic);
|
||||||
if (requestedProfiles == null) {
|
defaultNic = newDeviceInfo.first();
|
||||||
requestedProfiles = new ArrayList<NicProfile>();
|
deviceId = newDeviceInfo.second();
|
||||||
|
}
|
||||||
|
createExtraNics(size, nics, nextNetwork);
|
||||||
|
|
||||||
|
if (nics.size() == 1) {
|
||||||
|
nics.get(0).setDefaultNic(true);
|
||||||
}
|
}
|
||||||
if (requestedProfiles.isEmpty()) {
|
|
||||||
requestedProfiles.add(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final NicProfile requested : requestedProfiles) {
|
/**
|
||||||
|
* private transaction method to check and add devices to the nic list and update the info
|
||||||
|
*/
|
||||||
|
Pair<NicProfile,Integer> addRequestedNicToNicListWithDeviceNumberAndRetrieveDefaultDevice(NicProfile requested, boolean[] deviceIds, int deviceId, Network nextNetwork, List<NicProfile> nics, NicProfile defaultNic)
|
||||||
|
throws InsufficientAddressCapacityException, InsufficientVirtualNetworkCapacityException {
|
||||||
|
Pair<NicProfile, Integer> rc = new Pair<>(null,null);
|
||||||
Boolean isDefaultNic = false;
|
Boolean isDefaultNic = false;
|
||||||
if (vm != null && requested != null && requested.isDefaultNic()) {
|
if (vm != null && requested != null && requested.isDefaultNic()) {
|
||||||
isDefaultNic = true;
|
isDefaultNic = true;
|
||||||
@ -789,12 +798,12 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||||||
deviceId++;
|
deviceId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Pair<NicProfile, Integer> vmNicPair = allocateNic(requested, config, isDefaultNic, deviceId, vm);
|
final Pair<NicProfile, Integer> vmNicPair = allocateNic(requested, nextNetwork, isDefaultNic, deviceId, vm);
|
||||||
NicProfile vmNic = null;
|
NicProfile vmNic = null;
|
||||||
if (vmNicPair != null) {
|
if (vmNicPair != null) {
|
||||||
vmNic = vmNicPair.first();
|
vmNic = vmNicPair.first();
|
||||||
if (vmNic == null) {
|
if (vmNic == null) {
|
||||||
continue;
|
return rc;
|
||||||
}
|
}
|
||||||
deviceId = vmNicPair.second();
|
deviceId = vmNicPair.second();
|
||||||
}
|
}
|
||||||
@ -818,16 +827,92 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||||||
|
|
||||||
nics.add(vmNic);
|
nics.add(vmNic);
|
||||||
vm.addNic(vmNic);
|
vm.addNic(vmNic);
|
||||||
saveExtraDhcpOptions(config.getUuid(), vmNic.getId(), extraDhcpOptions);
|
saveExtraDhcpOptions(nextNetwork.getUuid(), vmNic.getId(), extraDhcpOptions);
|
||||||
}
|
rc.first(defaultNic);
|
||||||
}
|
rc.second(deviceId);
|
||||||
if (nics.size() != size) {
|
return rc;
|
||||||
s_logger.warn("Number of nics " + nics.size() + " doesn't match number of requested nics " + size);
|
|
||||||
throw new CloudRuntimeException("Number of nics " + nics.size() + " doesn't match number of requested networks " + size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nics.size() == 1) {
|
/**
|
||||||
nics.get(0).setDefaultNic(true);
|
* private transaction method to get oredered list of Network and NicProfile pair
|
||||||
|
* @return ordered list of Network and NicProfile pair
|
||||||
|
* @param networks the map od networks to nic profiles list
|
||||||
|
*/
|
||||||
|
private List<Pair<Network, NicProfile>> getOrderedNetworkNicProfileMapping(final LinkedHashMap<? extends Network, List<? extends NicProfile>> networks) {
|
||||||
|
List<Pair<Network, NicProfile>> profilesList = new ArrayList<>();
|
||||||
|
for (final Map.Entry<? extends Network, List<? extends NicProfile>> network : networks.entrySet()) {
|
||||||
|
List<? extends NicProfile> requestedProfiles = network.getValue();
|
||||||
|
if (requestedProfiles == null) {
|
||||||
|
requestedProfiles = new ArrayList<NicProfile>();
|
||||||
|
}
|
||||||
|
if (requestedProfiles.isEmpty()) {
|
||||||
|
requestedProfiles.add(null);
|
||||||
|
}
|
||||||
|
for (final NicProfile requested : requestedProfiles) {
|
||||||
|
profilesList.add(new Pair<Network, NicProfile>(network.getKey(), requested));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
profilesList.sort(new Comparator<Pair<Network, NicProfile>>() {
|
||||||
|
@Override
|
||||||
|
public int compare(Pair<Network, NicProfile> pair1, Pair<Network, NicProfile> pair2) {
|
||||||
|
int profile1Order = Integer.MAX_VALUE;
|
||||||
|
int profile2Order = Integer.MAX_VALUE;
|
||||||
|
if (pair1 != null && pair1.second() != null && pair1.second().getOrderIndex() != null) {
|
||||||
|
profile1Order = pair1.second().getOrderIndex();
|
||||||
|
}
|
||||||
|
if (pair2 != null && pair2.second() != null && pair2.second().getOrderIndex() != null) {
|
||||||
|
profile2Order = pair2.second().getOrderIndex();
|
||||||
|
}
|
||||||
|
return profile1Order - profile2Order;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return profilesList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* private transaction method to run over the objects and determine nic requirements
|
||||||
|
* @return the total numer of nics required
|
||||||
|
*/
|
||||||
|
private int determineNumberOfNicsRequired() {
|
||||||
|
int size = 0;
|
||||||
|
for (final Network ntwk : networks.keySet()) {
|
||||||
|
final List<? extends NicProfile> profiles = networks.get(ntwk);
|
||||||
|
if (profiles != null && !profiles.isEmpty()) {
|
||||||
|
size = size + profiles.size();
|
||||||
|
} else {
|
||||||
|
size = size + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<NetworkPrerequisiteTO> netprereqs = templateDetailsDao.listNetworkRequirementsByTemplateId(vm.getTemplate().getId());
|
||||||
|
if (size < netprereqs.size()) {
|
||||||
|
size = netprereqs.size();
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* private transaction method to add nics as required
|
||||||
|
* @param size the number needed
|
||||||
|
* @param nics the list of nics present
|
||||||
|
* @param finalNetwork the network to add the nics to
|
||||||
|
* @throws InsufficientVirtualNetworkCapacityException great
|
||||||
|
* @throws InsufficientAddressCapacityException also magnificent, as the name sugests
|
||||||
|
*/
|
||||||
|
private void createExtraNics(int size, List<NicProfile> nics, Network finalNetwork) throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException {
|
||||||
|
if (nics.size() != size) {
|
||||||
|
s_logger.warn("Number of nics " + nics.size() + " doesn't match number of requested nics " + size);
|
||||||
|
if (nics.size() > size) {
|
||||||
|
throw new CloudRuntimeException("Number of nics " + nics.size() + " doesn't match number of requested networks " + size);
|
||||||
|
} else {
|
||||||
|
if (finalNetwork == null) {
|
||||||
|
throw new CloudRuntimeException(String.format("can not assign network to %d remaining required NICs", size - nics.size()));
|
||||||
|
}
|
||||||
|
// create extra
|
||||||
|
for ( int extraNicNum = nics.size() ; extraNicNum < size; extraNicNum ++) {
|
||||||
|
final Pair<NicProfile, Integer> vmNicPair = allocateNic(new NicProfile(), finalNetwork, false, extraNicNum, vm);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -2364,12 +2449,12 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||||||
URI secondaryUri = isNotBlank(isolatedPvlan) ? BroadcastDomainType.fromString(isolatedPvlan) : null;
|
URI secondaryUri = isNotBlank(isolatedPvlan) ? BroadcastDomainType.fromString(isolatedPvlan) : null;
|
||||||
//don't allow to specify vlan tag used by physical network for dynamic vlan allocation
|
//don't allow to specify vlan tag used by physical network for dynamic vlan allocation
|
||||||
if (!(bypassVlanOverlapCheck && ntwkOff.getGuestType() == GuestType.Shared) && _dcDao.findVnet(zoneId, pNtwk.getId(), BroadcastDomainType.getValue(uri)).size() > 0) {
|
if (!(bypassVlanOverlapCheck && ntwkOff.getGuestType() == GuestType.Shared) && _dcDao.findVnet(zoneId, pNtwk.getId(), BroadcastDomainType.getValue(uri)).size() > 0) {
|
||||||
throw new InvalidParameterValueException("The VLAN tag " + vlanId + " is already being used for dynamic vlan allocation for the guest network in zone "
|
throw new InvalidParameterValueException("The VLAN tag to use for new guest network, " + vlanId + " is already being used for dynamic vlan allocation for the guest network in zone "
|
||||||
+ zone.getName());
|
+ zone.getName());
|
||||||
}
|
}
|
||||||
if (secondaryUri != null && !(bypassVlanOverlapCheck && ntwkOff.getGuestType() == GuestType.Shared) &&
|
if (secondaryUri != null && !(bypassVlanOverlapCheck && ntwkOff.getGuestType() == GuestType.Shared) &&
|
||||||
_dcDao.findVnet(zoneId, pNtwk.getId(), BroadcastDomainType.getValue(secondaryUri)).size() > 0) {
|
_dcDao.findVnet(zoneId, pNtwk.getId(), BroadcastDomainType.getValue(secondaryUri)).size() > 0) {
|
||||||
throw new InvalidParameterValueException("The VLAN tag " + isolatedPvlan + " is already being used for dynamic vlan allocation for the guest network in zone "
|
throw new InvalidParameterValueException("The VLAN tag for isolated PVLAN " + isolatedPvlan + " is already being used for dynamic vlan allocation for the guest network in zone "
|
||||||
+ zone.getName());
|
+ zone.getName());
|
||||||
}
|
}
|
||||||
if (! UuidUtils.validateUUID(vlanId)){
|
if (! UuidUtils.validateUUID(vlanId)){
|
||||||
|
|||||||
@ -19,6 +19,7 @@
|
|||||||
package org.apache.cloudstack.engine.orchestration;
|
package org.apache.cloudstack.engine.orchestration;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -26,10 +27,18 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.to.DatadiskTO;
|
||||||
|
import com.cloud.storage.VolumeDetailVO;
|
||||||
|
import com.cloud.storage.dao.VMTemplateDetailsDao;
|
||||||
|
import com.cloud.utils.StringUtils;
|
||||||
|
import com.cloud.vm.UserVmDetailVO;
|
||||||
|
import com.cloud.vm.VmDetailConstants;
|
||||||
|
import com.cloud.vm.dao.UserVmDetailsDao;
|
||||||
import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd;
|
import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.volume.MigrateVolumeCmdByAdmin;
|
import org.apache.cloudstack.api.command.admin.volume.MigrateVolumeCmdByAdmin;
|
||||||
import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
|
import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
|
||||||
@ -51,6 +60,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
|
|||||||
import org.apache.cloudstack.engine.subsystem.api.storage.StorageStrategyFactory;
|
import org.apache.cloudstack.engine.subsystem.api.storage.StorageStrategyFactory;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory;
|
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
|
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
|
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
|
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService;
|
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService;
|
||||||
@ -68,6 +78,7 @@ import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
|
|||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
|
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import com.cloud.agent.api.to.DataTO;
|
import com.cloud.agent.api.to.DataTO;
|
||||||
@ -141,6 +152,8 @@ import com.cloud.vm.dao.UserVmCloneSettingDao;
|
|||||||
import com.cloud.vm.dao.UserVmDao;
|
import com.cloud.vm.dao.UserVmDao;
|
||||||
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
|
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
|
||||||
|
|
||||||
|
import static com.cloud.storage.resource.StorageProcessor.REQUEST_TEMPLATE_RELOAD;
|
||||||
|
|
||||||
public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrationService, Configurable {
|
public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrationService, Configurable {
|
||||||
|
|
||||||
public enum UserVmCloneType {
|
public enum UserVmCloneType {
|
||||||
@ -197,6 +210,12 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
|
|||||||
protected UserVmCloneSettingDao _vmCloneSettingDao;
|
protected UserVmCloneSettingDao _vmCloneSettingDao;
|
||||||
@Inject
|
@Inject
|
||||||
StorageStrategyFactory _storageStrategyFactory;
|
StorageStrategyFactory _storageStrategyFactory;
|
||||||
|
@Inject
|
||||||
|
VMTemplateDetailsDao templateDetailsDao;
|
||||||
|
@Inject
|
||||||
|
TemplateService templateService;
|
||||||
|
@Inject
|
||||||
|
UserVmDetailsDao userVmDetailsDao;
|
||||||
|
|
||||||
private final StateMachine2<Volume.State, Volume.Event, Volume> _volStateMachine;
|
private final StateMachine2<Volume.State, Volume.Event, Volume> _volStateMachine;
|
||||||
protected List<StoragePoolAllocator> _storagePoolAllocators;
|
protected List<StoragePoolAllocator> _storagePoolAllocators;
|
||||||
@ -591,7 +610,7 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
|
|||||||
try {
|
try {
|
||||||
VolumeApiResult result = future.get();
|
VolumeApiResult result = future.get();
|
||||||
if (result.isFailed()) {
|
if (result.isFailed()) {
|
||||||
if (result.getResult().contains("request template reload") && (i == 0)) {
|
if (result.getResult().contains(REQUEST_TEMPLATE_RELOAD) && (i == 0)) {
|
||||||
s_logger.debug("Retry template re-deploy for vmware");
|
s_logger.debug("Retry template re-deploy for vmware");
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
@ -734,19 +753,23 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
|
|||||||
return toDiskProfile(vol, offering);
|
return toDiskProfile(vol, offering);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering offering, Long rootDisksize, Long minIops, Long maxIops, VirtualMachineTemplate template, VirtualMachine vm,
|
||||||
public DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering offering, Long rootDisksize, Long minIops, Long maxIops, VirtualMachineTemplate template, VirtualMachine vm,
|
Account owner, long deviceId, String configurationId) {
|
||||||
Account owner) {
|
|
||||||
assert (template.getFormat() != ImageFormat.ISO) : "ISO is not a template really....";
|
assert (template.getFormat() != ImageFormat.ISO) : "ISO is not a template really....";
|
||||||
|
|
||||||
Long size = _tmpltMgr.getTemplateSize(template.getId(), vm.getDataCenterId());
|
Long size = _tmpltMgr.getTemplateSize(template.getId(), vm.getDataCenterId());
|
||||||
if (rootDisksize != null) {
|
if (rootDisksize != null) {
|
||||||
|
if (template.isDeployAsIs()) {
|
||||||
|
// Volume size specified from template deploy-as-is
|
||||||
|
size = rootDisksize;
|
||||||
|
} else {
|
||||||
rootDisksize = rootDisksize * 1024 * 1024 * 1024;
|
rootDisksize = rootDisksize * 1024 * 1024 * 1024;
|
||||||
if (rootDisksize > size) {
|
if (rootDisksize > size) {
|
||||||
s_logger.debug("Using root disk size of " + toHumanReadableSize(rootDisksize) + " Bytes for volume " + name);
|
s_logger.debug("Using root disk size of " + toHumanReadableSize(rootDisksize) + " Bytes for volume " + name);
|
||||||
size = rootDisksize;
|
size = rootDisksize;
|
||||||
} else {
|
} else {
|
||||||
s_logger.debug("Using root disk size of " + toHumanReadableSize(size) + " Bytes for volume " + name + "since specified root disk size of " + toHumanReadableSize(rootDisksize) + " Bytes is smaller than template");
|
s_logger.debug("Using root disk size of " + toHumanReadableSize(rootDisksize) + " Bytes for volume " + name + "since specified root disk size of " + rootDisksize + " Bytes is smaller than template");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -760,14 +783,10 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
|
|||||||
}
|
}
|
||||||
vol.setTemplateId(template.getId());
|
vol.setTemplateId(template.getId());
|
||||||
|
|
||||||
if (type.equals(Type.ROOT)) {
|
vol.setDeviceId(deviceId);
|
||||||
vol.setDeviceId(0l);
|
if (type.equals(Type.ROOT) && !vm.getType().equals(VirtualMachine.Type.User)) {
|
||||||
if (!vm.getType().equals(VirtualMachine.Type.User)) {
|
|
||||||
vol.setRecreatable(true);
|
vol.setRecreatable(true);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
vol.setDeviceId(1l);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vm.getType() == VirtualMachine.Type.User) {
|
if (vm.getType() == VirtualMachine.Type.User) {
|
||||||
UserVmVO userVm = _userVmDao.findById(vm.getId());
|
UserVmVO userVm = _userVmDao.findById(vm.getId());
|
||||||
@ -776,6 +795,11 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
|
|||||||
|
|
||||||
vol = _volsDao.persist(vol);
|
vol = _volsDao.persist(vol);
|
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(configurationId)) {
|
||||||
|
VolumeDetailVO deployConfigurationDetail = new VolumeDetailVO(vol.getId(), VmDetailConstants.DEPLOY_AS_IS_CONFIGURATION, configurationId, false);
|
||||||
|
_volDetailDao.persist(deployConfigurationDetail);
|
||||||
|
}
|
||||||
|
|
||||||
// Create event and update resource count for volumes if vm is a user vm
|
// Create event and update resource count for volumes if vm is a user vm
|
||||||
if (vm.getType() == VirtualMachine.Type.User) {
|
if (vm.getType() == VirtualMachine.Type.User) {
|
||||||
|
|
||||||
@ -794,6 +818,51 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
|
|||||||
return toDiskProfile(vol, offering);
|
return toDiskProfile(vol, offering);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DiskProfile> allocateTemplatedVolumes(Type type, String name, DiskOffering offering, Long rootDisksize, Long minIops, Long maxIops, VirtualMachineTemplate template, VirtualMachine vm,
|
||||||
|
Account owner) {
|
||||||
|
int volumesNumber = 1;
|
||||||
|
List<DatadiskTO> templateAsIsDisks = null;
|
||||||
|
String configurationId = null;
|
||||||
|
if (template.isDeployAsIs()) {
|
||||||
|
UserVmDetailVO configurationDetail = userVmDetailsDao.findDetail(vm.getId(), VmDetailConstants.DEPLOY_AS_IS_CONFIGURATION);
|
||||||
|
if (configurationDetail != null) {
|
||||||
|
configurationId = configurationDetail.getValue();
|
||||||
|
}
|
||||||
|
templateAsIsDisks = _tmpltMgr.getTemplateDisksOnImageStore(template.getId(), DataStoreRole.Image, configurationId);
|
||||||
|
if (CollectionUtils.isNotEmpty(templateAsIsDisks)) {
|
||||||
|
templateAsIsDisks = templateAsIsDisks.stream()
|
||||||
|
.filter(x -> !x.isIso())
|
||||||
|
.sorted(Comparator.comparing(DatadiskTO::getDiskNumber))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
volumesNumber = templateAsIsDisks.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (volumesNumber < 1) {
|
||||||
|
throw new CloudRuntimeException("Unable to create any volume from template " + template.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<DiskProfile> profiles = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int number = 0; number < volumesNumber; number++) {
|
||||||
|
String volumeName = name;
|
||||||
|
Long volumeSize = rootDisksize;
|
||||||
|
long deviceId = type.equals(Type.ROOT) ? 0L : 1L;
|
||||||
|
if (template.isDeployAsIs()) {
|
||||||
|
int volumeNameSuffix = templateAsIsDisks.get(number).getDiskNumber();
|
||||||
|
volumeName = String.format("%s-%d", volumeName, volumeNameSuffix);
|
||||||
|
volumeSize = templateAsIsDisks.get(number).getVirtualSize();
|
||||||
|
deviceId = templateAsIsDisks.get(number).getDiskNumber();
|
||||||
|
}
|
||||||
|
s_logger.info(String.format("adding disk object %s to %s", volumeName, vm.getInstanceName()));
|
||||||
|
DiskProfile diskProfile = allocateTemplatedVolume(type, volumeName, offering, volumeSize, minIops, maxIops,
|
||||||
|
template, vm, owner, deviceId, configurationId);
|
||||||
|
profiles.add(diskProfile);
|
||||||
|
}
|
||||||
|
return profiles;
|
||||||
|
}
|
||||||
|
|
||||||
private ImageFormat getSupportedImageFormatForCluster(HypervisorType hyperType) {
|
private ImageFormat getSupportedImageFormatForCluster(HypervisorType hyperType) {
|
||||||
if (hyperType == HypervisorType.XenServer) {
|
if (hyperType == HypervisorType.XenServer) {
|
||||||
return ImageFormat.VHD;
|
return ImageFormat.VHD;
|
||||||
@ -1356,7 +1425,7 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
|
|||||||
try {
|
try {
|
||||||
result = future.get();
|
result = future.get();
|
||||||
if (result.isFailed()) {
|
if (result.isFailed()) {
|
||||||
if (result.getResult().contains("request template reload") && (i == 0)) {
|
if (result.getResult().contains(REQUEST_TEMPLATE_RELOAD) && (i == 0)) {
|
||||||
s_logger.debug("Retry template re-deploy for vmware");
|
s_logger.debug("Retry template re-deploy for vmware");
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -1,167 +0,0 @@
|
|||||||
// 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.storage;
|
|
||||||
|
|
||||||
import com.cloud.agent.api.storage.OVFProperty;
|
|
||||||
|
|
||||||
import javax.persistence.Column;
|
|
||||||
import javax.persistence.Entity;
|
|
||||||
import javax.persistence.GeneratedValue;
|
|
||||||
import javax.persistence.GenerationType;
|
|
||||||
import javax.persistence.Id;
|
|
||||||
import javax.persistence.Table;
|
|
||||||
|
|
||||||
@Entity
|
|
||||||
@Table(name = "template_ovf_properties")
|
|
||||||
public class TemplateOVFPropertyVO implements OVFProperty {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
|
||||||
@Column(name = "id")
|
|
||||||
private long id;
|
|
||||||
|
|
||||||
@Column(name = "template_id")
|
|
||||||
private Long templateId;
|
|
||||||
|
|
||||||
@Column(name = "key")
|
|
||||||
private String key;
|
|
||||||
|
|
||||||
@Column(name = "type")
|
|
||||||
private String type;
|
|
||||||
|
|
||||||
@Column(name = "value")
|
|
||||||
private String value;
|
|
||||||
|
|
||||||
@Column(name = "qualifiers")
|
|
||||||
private String qualifiers;
|
|
||||||
|
|
||||||
@Column(name = "password")
|
|
||||||
private Boolean password;
|
|
||||||
|
|
||||||
@Column(name = "user_configurable")
|
|
||||||
private Boolean userConfigurable;
|
|
||||||
|
|
||||||
@Column(name = "label")
|
|
||||||
private String label;
|
|
||||||
|
|
||||||
@Column(name = "description")
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
public TemplateOVFPropertyVO() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public TemplateOVFPropertyVO(Long templateId, String key, String type, String value, String qualifiers,
|
|
||||||
Boolean userConfigurable, String label, String description, Boolean password) {
|
|
||||||
this.templateId = templateId;
|
|
||||||
this.key = key;
|
|
||||||
this.type = type;
|
|
||||||
this.value = value;
|
|
||||||
this.qualifiers = qualifiers;
|
|
||||||
this.userConfigurable = userConfigurable;
|
|
||||||
this.label = label;
|
|
||||||
this.description = description;
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(long id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getTemplateId() {
|
|
||||||
return templateId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTemplateId(Long templateId) {
|
|
||||||
this.templateId = templateId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getKey() {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setKey(String key) {
|
|
||||||
this.key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setType(String type) {
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setValue(String value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getQualifiers() {
|
|
||||||
return qualifiers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setQualifiers(String qualifiers) {
|
|
||||||
this.qualifiers = qualifiers;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean isUserConfigurable() {
|
|
||||||
return userConfigurable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUserConfigurable(Boolean userConfigurable) {
|
|
||||||
this.userConfigurable = userConfigurable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLabel() {
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLabel(String label) {
|
|
||||||
this.label = label;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescription() {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDescription(String description) {
|
|
||||||
this.description = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean isPassword() {
|
|
||||||
return password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPassword(Boolean password) {
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format("PROP - templateId=%s> key=%s value=%s type=%s qual=%s conf=%s label=%s desc=%s password=%s",
|
|
||||||
templateId, key, value, type, qualifiers, userConfigurable, label, description, password);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -21,6 +21,7 @@ import javax.persistence.Entity;
|
|||||||
import javax.persistence.GeneratedValue;
|
import javax.persistence.GeneratedValue;
|
||||||
import javax.persistence.GenerationType;
|
import javax.persistence.GenerationType;
|
||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Lob;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
|
|
||||||
import org.apache.cloudstack.api.ResourceDetail;
|
import org.apache.cloudstack.api.ResourceDetail;
|
||||||
@ -39,7 +40,8 @@ public class VMTemplateDetailVO implements ResourceDetail {
|
|||||||
@Column(name = "name")
|
@Column(name = "name")
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@Column(name = "value", length = 1024)
|
@Lob
|
||||||
|
@Column(name = "value", length = 65535)
|
||||||
private String value;
|
private String value;
|
||||||
|
|
||||||
@Column(name = "display")
|
@Column(name = "display")
|
||||||
|
|||||||
@ -95,6 +95,9 @@ public class VMTemplateStoragePoolVO implements VMTemplateStorageResourceAssoc,
|
|||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
ObjectInDataStoreStateMachine.State state;
|
ObjectInDataStoreStateMachine.State state;
|
||||||
|
|
||||||
|
@Column(name = "deployment_option")
|
||||||
|
private String deploymentOption;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getInstallPath() {
|
public String getInstallPath() {
|
||||||
return installPath;
|
return installPath;
|
||||||
@ -168,17 +171,18 @@ public class VMTemplateStoragePoolVO implements VMTemplateStorageResourceAssoc,
|
|||||||
return downloadState;
|
return downloadState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public VMTemplateStoragePoolVO(long poolId, long templateId) {
|
public VMTemplateStoragePoolVO(long poolId, long templateId, String configuration) {
|
||||||
super();
|
super();
|
||||||
this.poolId = poolId;
|
this.poolId = poolId;
|
||||||
this.templateId = templateId;
|
this.templateId = templateId;
|
||||||
this.downloadState = Status.NOT_DOWNLOADED;
|
this.downloadState = Status.NOT_DOWNLOADED;
|
||||||
this.state = ObjectInDataStoreStateMachine.State.Allocated;
|
this.state = ObjectInDataStoreStateMachine.State.Allocated;
|
||||||
this.markedForGC = false;
|
this.markedForGC = false;
|
||||||
|
this.deploymentOption = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public VMTemplateStoragePoolVO(long poolId, long templateId, Date lastUpdated, int downloadPercent, Status downloadState, String localDownloadPath,
|
public VMTemplateStoragePoolVO(long poolId, long templateId, Date lastUpdated, int downloadPercent, Status downloadState, String localDownloadPath,
|
||||||
String errorString, String jobId, String installPath, long templateSize) {
|
String errorString, String jobId, String installPath, long templateSize, String configuration) {
|
||||||
super();
|
super();
|
||||||
this.poolId = poolId;
|
this.poolId = poolId;
|
||||||
this.templateId = templateId;
|
this.templateId = templateId;
|
||||||
@ -190,6 +194,7 @@ public class VMTemplateStoragePoolVO implements VMTemplateStorageResourceAssoc,
|
|||||||
this.jobId = jobId;
|
this.jobId = jobId;
|
||||||
this.installPath = installPath;
|
this.installPath = installPath;
|
||||||
this.templateSize = templateSize;
|
this.templateSize = templateSize;
|
||||||
|
this.deploymentOption = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected VMTemplateStoragePoolVO() {
|
protected VMTemplateStoragePoolVO() {
|
||||||
@ -300,4 +305,11 @@ public class VMTemplateStoragePoolVO implements VMTemplateStorageResourceAssoc,
|
|||||||
return this.state;
|
return this.state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getDeploymentOption() {
|
||||||
|
return deploymentOption;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeploymentOption(String deploymentOption) {
|
||||||
|
this.deploymentOption = deploymentOption;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -152,6 +152,9 @@ public class VMTemplateVO implements VirtualMachineTemplate {
|
|||||||
@Column(name = "parent_template_id")
|
@Column(name = "parent_template_id")
|
||||||
private Long parentTemplateId;
|
private Long parentTemplateId;
|
||||||
|
|
||||||
|
@Column(name = "deploy_as_is")
|
||||||
|
private boolean deployAsIs;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUniqueName() {
|
public String getUniqueName() {
|
||||||
return uniqueName;
|
return uniqueName;
|
||||||
@ -192,9 +195,9 @@ public class VMTemplateVO implements VirtualMachineTemplate {
|
|||||||
uuid = UUID.randomUUID().toString();
|
uuid = UUID.randomUUID().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public VMTemplateVO(long id, String name, ImageFormat format, boolean isPublic, boolean featured, boolean isExtractable, TemplateType type, String url,
|
public VMTemplateVO(long id, String name, ImageFormat format, boolean isPublic, boolean featured, boolean isExtractable, TemplateType type, String url, boolean requiresHvm, int bits, long accountId, String cksum, String displayText, boolean enablePassword, long guestOSId, boolean bootable,
|
||||||
boolean requiresHvm, int bits, long accountId, String cksum, String displayText, boolean enablePassword, long guestOSId, boolean bootable,
|
HypervisorType hyperType, String templateTag, Map<String, String> details, boolean sshKeyEnabled, boolean isDynamicallyScalable, boolean directDownload,
|
||||||
HypervisorType hyperType, String templateTag, Map<String, String> details, boolean sshKeyEnabled, boolean isDynamicallyScalable, boolean directDownload) {
|
boolean deployAsIs) {
|
||||||
this(id,
|
this(id,
|
||||||
name,
|
name,
|
||||||
format,
|
format,
|
||||||
@ -219,6 +222,7 @@ public class VMTemplateVO implements VirtualMachineTemplate {
|
|||||||
dynamicallyScalable = isDynamicallyScalable;
|
dynamicallyScalable = isDynamicallyScalable;
|
||||||
state = State.Active;
|
state = State.Active;
|
||||||
this.directDownload = directDownload;
|
this.directDownload = directDownload;
|
||||||
|
this.deployAsIs = deployAsIs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static VMTemplateVO createPreHostIso(Long id, String uniqueName, String name, ImageFormat format, boolean isPublic, boolean featured, TemplateType type,
|
public static VMTemplateVO createPreHostIso(Long id, String uniqueName, String name, ImageFormat format, boolean isPublic, boolean featured, TemplateType type,
|
||||||
@ -637,4 +641,11 @@ public class VMTemplateVO implements VirtualMachineTemplate {
|
|||||||
this.parentTemplateId = parentTemplateId;
|
this.parentTemplateId = parentTemplateId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public boolean isDeployAsIs() {
|
||||||
|
return deployAsIs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeployAsIs(boolean deployAsIs) {
|
||||||
|
this.deployAsIs = deployAsIs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,78 +0,0 @@
|
|||||||
// 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.storage.dao;
|
|
||||||
|
|
||||||
import com.cloud.storage.TemplateOVFPropertyVO;
|
|
||||||
import com.cloud.utils.db.GenericDaoBase;
|
|
||||||
import com.cloud.utils.db.SearchBuilder;
|
|
||||||
import com.cloud.utils.db.SearchCriteria;
|
|
||||||
import com.cloud.utils.db.TransactionLegacy;
|
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
public class TemplateOVFPropertiesDaoImpl extends GenericDaoBase<TemplateOVFPropertyVO, Long> implements TemplateOVFPropertiesDao {
|
|
||||||
|
|
||||||
private final static Logger s_logger = Logger.getLogger(TemplateOVFPropertiesDaoImpl.class);
|
|
||||||
|
|
||||||
SearchBuilder<TemplateOVFPropertyVO> OptionsSearchBuilder;
|
|
||||||
|
|
||||||
public TemplateOVFPropertiesDaoImpl() {
|
|
||||||
super();
|
|
||||||
OptionsSearchBuilder = createSearchBuilder();
|
|
||||||
OptionsSearchBuilder.and("templateid", OptionsSearchBuilder.entity().getTemplateId(), SearchCriteria.Op.EQ);
|
|
||||||
OptionsSearchBuilder.and("key", OptionsSearchBuilder.entity().getKey(), SearchCriteria.Op.EQ);
|
|
||||||
OptionsSearchBuilder.done();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean existsOption(long templateId, String key) {
|
|
||||||
return findByTemplateAndKey(templateId, key) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TemplateOVFPropertyVO findByTemplateAndKey(long templateId, String key) {
|
|
||||||
SearchCriteria<TemplateOVFPropertyVO> sc = OptionsSearchBuilder.create();
|
|
||||||
sc.setParameters("templateid", templateId);
|
|
||||||
sc.setParameters("key", key);
|
|
||||||
return findOneBy(sc);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void saveOptions(List<TemplateOVFPropertyVO> opts) {
|
|
||||||
if (CollectionUtils.isEmpty(opts)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
|
||||||
txn.start();
|
|
||||||
for (TemplateOVFPropertyVO opt : opts) {
|
|
||||||
persist(opt);
|
|
||||||
}
|
|
||||||
txn.commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<TemplateOVFPropertyVO> listByTemplateId(long templateId) {
|
|
||||||
SearchCriteria<TemplateOVFPropertyVO> sc = OptionsSearchBuilder.create();
|
|
||||||
sc.setParameters("templateid", templateId);
|
|
||||||
return listBy(sc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -16,11 +16,25 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.storage.dao;
|
package com.cloud.storage.dao;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.storage.OVFPropertyTO;
|
||||||
|
import com.cloud.agent.api.to.DatadiskTO;
|
||||||
|
import org.apache.cloudstack.api.net.NetworkPrerequisiteTO;
|
||||||
import org.apache.cloudstack.resourcedetail.ResourceDetailsDao;
|
import org.apache.cloudstack.resourcedetail.ResourceDetailsDao;
|
||||||
|
|
||||||
import com.cloud.storage.VMTemplateDetailVO;
|
import com.cloud.storage.VMTemplateDetailVO;
|
||||||
import com.cloud.utils.db.GenericDao;
|
import com.cloud.utils.db.GenericDao;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public interface VMTemplateDetailsDao extends GenericDao<VMTemplateDetailVO, Long>, ResourceDetailsDao<VMTemplateDetailVO> {
|
public interface VMTemplateDetailsDao extends GenericDao<VMTemplateDetailVO, Long>, ResourceDetailsDao<VMTemplateDetailVO> {
|
||||||
|
|
||||||
|
boolean existsOption(long templateId, String key);
|
||||||
|
OVFPropertyTO findPropertyByTemplateAndKey(long templateId, String key);
|
||||||
|
void saveOptions(List<OVFPropertyTO> opts);
|
||||||
|
List<OVFPropertyTO> listPropertiesByTemplateId(long templateId);
|
||||||
|
List<NetworkPrerequisiteTO> listNetworkRequirementsByTemplateId(long templateId);
|
||||||
|
List<DatadiskTO> listDisksByTemplateId(long templateId);
|
||||||
|
|
||||||
|
List<VMTemplateDetailVO> listDetailsByTemplateIdMatchingPrefix(long templateId, String prefix);
|
||||||
|
String getTemplateEulaSectionsUrl(long templateId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,17 +17,137 @@
|
|||||||
package com.cloud.storage.dao;
|
package com.cloud.storage.dao;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.net.NetworkPrerequisiteTO;
|
||||||
|
import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase;
|
import com.cloud.agent.api.storage.OVFPropertyTO;
|
||||||
|
import com.cloud.agent.api.to.DatadiskTO;
|
||||||
|
import com.cloud.storage.ImageStore;
|
||||||
import com.cloud.storage.VMTemplateDetailVO;
|
import com.cloud.storage.VMTemplateDetailVO;
|
||||||
|
import com.cloud.utils.db.SearchBuilder;
|
||||||
|
import com.cloud.utils.db.SearchCriteria;
|
||||||
|
import com.cloud.utils.db.TransactionLegacy;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class VMTemplateDetailsDaoImpl extends ResourceDetailsDaoBase<VMTemplateDetailVO> implements VMTemplateDetailsDao {
|
public class VMTemplateDetailsDaoImpl extends ResourceDetailsDaoBase<VMTemplateDetailVO> implements VMTemplateDetailsDao {
|
||||||
|
|
||||||
|
private final static Logger LOGGER = Logger.getLogger(VMTemplateDetailsDaoImpl.class);
|
||||||
|
|
||||||
|
Gson gson = new Gson();
|
||||||
|
|
||||||
|
SearchBuilder<VMTemplateDetailVO> OptionsSearchBuilder;
|
||||||
|
|
||||||
|
public VMTemplateDetailsDaoImpl() {
|
||||||
|
super();
|
||||||
|
OptionsSearchBuilder = createSearchBuilder();
|
||||||
|
OptionsSearchBuilder.and("resourceId", OptionsSearchBuilder.entity().getResourceId(), SearchCriteria.Op.EQ);
|
||||||
|
OptionsSearchBuilder.and("name", OptionsSearchBuilder.entity().getName(), SearchCriteria.Op.EQ);
|
||||||
|
OptionsSearchBuilder.done();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addDetail(long resourceId, String key, String value, boolean display) {
|
public void addDetail(long resourceId, String key, String value, boolean display) {
|
||||||
super.addDetail(new VMTemplateDetailVO(resourceId, key, value, display));
|
super.addDetail(new VMTemplateDetailVO(resourceId, key, value, display));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean existsOption(long templateId, String key) {
|
||||||
|
return findPropertyByTemplateAndKey(templateId, key) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OVFPropertyTO findPropertyByTemplateAndKey(long templateId, String key) {
|
||||||
|
SearchCriteria<VMTemplateDetailVO> sc = OptionsSearchBuilder.create();
|
||||||
|
sc.setParameters("resourceId", templateId);
|
||||||
|
sc.setParameters("name", key.startsWith(ImageStore.ACS_PROPERTY_PREFIX) ? key : ImageStore.ACS_PROPERTY_PREFIX + key);
|
||||||
|
OVFPropertyTO property = null;
|
||||||
|
VMTemplateDetailVO detail = findOneBy(sc);
|
||||||
|
if (detail != null) {
|
||||||
|
property = gson.fromJson(detail.getValue(), OVFPropertyTO.class);
|
||||||
|
}
|
||||||
|
return property;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveOptions(List<OVFPropertyTO> opts) {
|
||||||
|
if (CollectionUtils.isEmpty(opts)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
||||||
|
txn.start();
|
||||||
|
for (OVFPropertyTO opt : opts) {
|
||||||
|
String json = gson.toJson(opt);
|
||||||
|
VMTemplateDetailVO templateDetailVO = new VMTemplateDetailVO(opt.getTemplateId(), ImageStore.ACS_PROPERTY_PREFIX + opt.getKey(), json, opt.isUserConfigurable());
|
||||||
|
persist(templateDetailVO);
|
||||||
|
}
|
||||||
|
txn.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<OVFPropertyTO> listPropertiesByTemplateId(long templateId) {
|
||||||
|
List<VMTemplateDetailVO> ovfProperties = listDetailsByTemplateIdMatchingPrefix(templateId, ImageStore.ACS_PROPERTY_PREFIX);
|
||||||
|
List<OVFPropertyTO> properties = new ArrayList<>();
|
||||||
|
for (VMTemplateDetailVO property : ovfProperties) {
|
||||||
|
OVFPropertyTO ovfPropertyTO = gson.fromJson(property.getValue(), OVFPropertyTO.class);
|
||||||
|
properties.add(ovfPropertyTO);
|
||||||
|
}
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<NetworkPrerequisiteTO> listNetworkRequirementsByTemplateId(long templateId) {
|
||||||
|
List<VMTemplateDetailVO> networkDetails = listDetailsByTemplateIdMatchingPrefix(templateId, ImageStore.REQUIRED_NETWORK_PREFIX);
|
||||||
|
List<NetworkPrerequisiteTO> networkPrereqs = new ArrayList<>();
|
||||||
|
for (VMTemplateDetailVO property : networkDetails) {
|
||||||
|
NetworkPrerequisiteTO ovfPropertyTO = gson.fromJson(property.getValue(), NetworkPrerequisiteTO.class);
|
||||||
|
networkPrereqs.add(ovfPropertyTO);
|
||||||
|
}
|
||||||
|
networkPrereqs.sort(new Comparator<NetworkPrerequisiteTO>() {
|
||||||
|
@Override
|
||||||
|
public int compare(NetworkPrerequisiteTO o1, NetworkPrerequisiteTO o2) {
|
||||||
|
return o1.getInstanceID() - o2.getInstanceID();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return networkPrereqs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DatadiskTO> listDisksByTemplateId(long templateId) {
|
||||||
|
List<VMTemplateDetailVO> diskDefinitions = listDetailsByTemplateIdMatchingPrefix(templateId, ImageStore.DISK_DEFINITION_PREFIX);
|
||||||
|
List<DatadiskTO> disks = new ArrayList<>();
|
||||||
|
for (VMTemplateDetailVO detail : diskDefinitions) {
|
||||||
|
DatadiskTO datadiskTO = gson.fromJson(detail.getValue(), DatadiskTO.class);
|
||||||
|
disks.add(datadiskTO);
|
||||||
|
}
|
||||||
|
return disks;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<VMTemplateDetailVO> listDetailsByTemplateIdMatchingPrefix(long templateId, String prefix) {
|
||||||
|
SearchCriteria<VMTemplateDetailVO> ssc = createSearchCriteria();
|
||||||
|
ssc.addAnd("resourceId", SearchCriteria.Op.EQ, templateId);
|
||||||
|
ssc.addAnd("name", SearchCriteria.Op.LIKE, prefix + "%");
|
||||||
|
|
||||||
|
return search(ssc, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTemplateEulaSectionsUrl(long templateId) {
|
||||||
|
List<VMTemplateDetailVO> details = findDetails(templateId, ImageStore.OVF_EULA_SECTION_PREFIX);
|
||||||
|
if (CollectionUtils.isEmpty(details)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (details.size() > 1) {
|
||||||
|
LOGGER.error("Multiple details for EULA sections for template " + templateId + " returning one");
|
||||||
|
}
|
||||||
|
return details.get(0).getValue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -27,27 +27,27 @@ import com.cloud.utils.fsm.StateDao;
|
|||||||
|
|
||||||
public interface VMTemplatePoolDao extends GenericDao<VMTemplateStoragePoolVO, Long>,
|
public interface VMTemplatePoolDao extends GenericDao<VMTemplateStoragePoolVO, Long>,
|
||||||
StateDao<ObjectInDataStoreStateMachine.State, ObjectInDataStoreStateMachine.Event, DataObjectInStore> {
|
StateDao<ObjectInDataStoreStateMachine.State, ObjectInDataStoreStateMachine.Event, DataObjectInStore> {
|
||||||
public List<VMTemplateStoragePoolVO> listByPoolId(long id);
|
List<VMTemplateStoragePoolVO> listByPoolId(long id);
|
||||||
|
|
||||||
public List<VMTemplateStoragePoolVO> listByTemplateId(long templateId);
|
List<VMTemplateStoragePoolVO> listByTemplateId(long templateId);
|
||||||
|
|
||||||
public VMTemplateStoragePoolVO findByPoolTemplate(long poolId, long templateId);
|
VMTemplateStoragePoolVO findByPoolTemplate(long poolId, long templateId, String configuration);
|
||||||
|
|
||||||
public List<VMTemplateStoragePoolVO> listByPoolIdAndState(long poolId, ObjectInDataStoreStateMachine.State state);
|
List<VMTemplateStoragePoolVO> listByPoolIdAndState(long poolId, ObjectInDataStoreStateMachine.State state);
|
||||||
|
|
||||||
public List<VMTemplateStoragePoolVO> listByTemplateStatus(long templateId, VMTemplateStoragePoolVO.Status downloadState);
|
List<VMTemplateStoragePoolVO> listByTemplateStatus(long templateId, VMTemplateStoragePoolVO.Status downloadState);
|
||||||
|
|
||||||
public List<VMTemplateStoragePoolVO> listByTemplateStatus(long templateId, VMTemplateStoragePoolVO.Status downloadState, long poolId);
|
List<VMTemplateStoragePoolVO> listByTemplateStatus(long templateId, VMTemplateStoragePoolVO.Status downloadState, long poolId);
|
||||||
|
|
||||||
public List<VMTemplateStoragePoolVO> listByTemplateStatus(long templateId, long datacenterId, VMTemplateStoragePoolVO.Status downloadState);
|
List<VMTemplateStoragePoolVO> listByTemplateStatus(long templateId, long datacenterId, VMTemplateStoragePoolVO.Status downloadState);
|
||||||
|
|
||||||
public List<VMTemplateStoragePoolVO> listByTemplateStatus(long templateId, long datacenterId, long podId, VMTemplateStoragePoolVO.Status downloadState);
|
List<VMTemplateStoragePoolVO> listByTemplateStatus(long templateId, long datacenterId, long podId, VMTemplateStoragePoolVO.Status downloadState);
|
||||||
|
|
||||||
public List<VMTemplateStoragePoolVO> listByTemplateStates(long templateId, VMTemplateStoragePoolVO.Status... states);
|
List<VMTemplateStoragePoolVO> listByTemplateStates(long templateId, VMTemplateStoragePoolVO.Status... states);
|
||||||
|
|
||||||
boolean templateAvailable(long templateId, long poolId);
|
boolean templateAvailable(long templateId, long poolId);
|
||||||
|
|
||||||
public VMTemplateStoragePoolVO findByHostTemplate(Long hostId, Long templateId);
|
VMTemplateStoragePoolVO findByHostTemplate(Long hostId, Long templateId, String configuration);
|
||||||
|
|
||||||
VMTemplateStoragePoolVO findByPoolPath(Long poolId, String path);
|
VMTemplateStoragePoolVO findByPoolPath(Long poolId, String path);
|
||||||
|
|
||||||
|
|||||||
@ -28,6 +28,7 @@ import javax.inject.Inject;
|
|||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
|
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@ -73,7 +74,7 @@ public class VMTemplatePoolDaoImpl extends GenericDaoBase<VMTemplateStoragePoolV
|
|||||||
|
|
||||||
protected static final String HOST_TEMPLATE_SEARCH =
|
protected static final String HOST_TEMPLATE_SEARCH =
|
||||||
"SELECT * FROM template_spool_ref tp, storage_pool_host_ref ph, host h where tp.pool_id = ph.pool_id and ph.host_id = h.id and h.id=? "
|
"SELECT * FROM template_spool_ref tp, storage_pool_host_ref ph, host h where tp.pool_id = ph.pool_id and ph.host_id = h.id and h.id=? "
|
||||||
+ " and tp.template_id=? ";
|
+ " and tp.template_id=? and tp.deployment_option ";
|
||||||
|
|
||||||
public VMTemplatePoolDaoImpl() {
|
public VMTemplatePoolDaoImpl() {
|
||||||
PoolSearch = createSearchBuilder();
|
PoolSearch = createSearchBuilder();
|
||||||
@ -87,6 +88,7 @@ public class VMTemplatePoolDaoImpl extends GenericDaoBase<VMTemplateStoragePoolV
|
|||||||
PoolTemplateSearch = createSearchBuilder();
|
PoolTemplateSearch = createSearchBuilder();
|
||||||
PoolTemplateSearch.and("pool_id", PoolTemplateSearch.entity().getPoolId(), SearchCriteria.Op.EQ);
|
PoolTemplateSearch.and("pool_id", PoolTemplateSearch.entity().getPoolId(), SearchCriteria.Op.EQ);
|
||||||
PoolTemplateSearch.and("template_id", PoolTemplateSearch.entity().getTemplateId(), SearchCriteria.Op.EQ);
|
PoolTemplateSearch.and("template_id", PoolTemplateSearch.entity().getTemplateId(), SearchCriteria.Op.EQ);
|
||||||
|
PoolTemplateSearch.and("configuration", PoolTemplateSearch.entity().getDeploymentOption(), SearchCriteria.Op.EQ);
|
||||||
PoolTemplateSearch.done();
|
PoolTemplateSearch.done();
|
||||||
|
|
||||||
TemplateStatusSearch = createSearchBuilder();
|
TemplateStatusSearch = createSearchBuilder();
|
||||||
@ -138,10 +140,13 @@ public class VMTemplatePoolDaoImpl extends GenericDaoBase<VMTemplateStoragePoolV
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VMTemplateStoragePoolVO findByPoolTemplate(long poolId, long templateId) {
|
public VMTemplateStoragePoolVO findByPoolTemplate(long poolId, long templateId, String configuration) {
|
||||||
SearchCriteria<VMTemplateStoragePoolVO> sc = PoolTemplateSearch.create();
|
SearchCriteria<VMTemplateStoragePoolVO> sc = PoolTemplateSearch.create();
|
||||||
sc.setParameters("pool_id", poolId);
|
sc.setParameters("pool_id", poolId);
|
||||||
sc.setParameters("template_id", templateId);
|
sc.setParameters("template_id", templateId);
|
||||||
|
if (StringUtils.isNotBlank(configuration)) {
|
||||||
|
sc.setParameters("configuration", configuration);
|
||||||
|
}
|
||||||
return findOneIncludingRemovedBy(sc);
|
return findOneIncludingRemovedBy(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,13 +224,17 @@ public class VMTemplatePoolDaoImpl extends GenericDaoBase<VMTemplateStoragePoolV
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<VMTemplateStoragePoolVO> listByHostTemplate(long hostId, long templateId) {
|
public List<VMTemplateStoragePoolVO> listByHostTemplate(long hostId, long templateId, String configuration) {
|
||||||
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
||||||
List<VMTemplateStoragePoolVO> result = new ArrayList<VMTemplateStoragePoolVO>();
|
List<VMTemplateStoragePoolVO> result = new ArrayList<VMTemplateStoragePoolVO>();
|
||||||
String sql = HOST_TEMPLATE_SEARCH;
|
String sql = HOST_TEMPLATE_SEARCH;
|
||||||
|
sql += StringUtils.isBlank(configuration) ? "IS NULL" : "= ?";
|
||||||
try(PreparedStatement pstmt = txn.prepareStatement(sql);) {
|
try(PreparedStatement pstmt = txn.prepareStatement(sql);) {
|
||||||
pstmt.setLong(1, hostId);
|
pstmt.setLong(1, hostId);
|
||||||
pstmt.setLong(2, templateId);
|
pstmt.setLong(2, templateId);
|
||||||
|
if (StringUtils.isNotBlank(configuration)) {
|
||||||
|
pstmt.setString(3, configuration);
|
||||||
|
}
|
||||||
try(ResultSet rs = pstmt.executeQuery();) {
|
try(ResultSet rs = pstmt.executeQuery();) {
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
// result.add(toEntityBean(rs, false)); TODO: this is buggy in
|
// result.add(toEntityBean(rs, false)); TODO: this is buggy in
|
||||||
@ -245,7 +254,7 @@ public class VMTemplatePoolDaoImpl extends GenericDaoBase<VMTemplateStoragePoolV
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean templateAvailable(long templateId, long hostId) {
|
public boolean templateAvailable(long templateId, long hostId) {
|
||||||
VMTemplateStorageResourceAssoc tmpltPool = findByPoolTemplate(hostId, templateId);
|
VMTemplateStorageResourceAssoc tmpltPool = findByPoolTemplate(hostId, templateId, null);
|
||||||
if (tmpltPool == null)
|
if (tmpltPool == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -262,9 +271,9 @@ public class VMTemplatePoolDaoImpl extends GenericDaoBase<VMTemplateStoragePoolV
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VMTemplateStoragePoolVO findByHostTemplate(Long hostId, Long templateId) {
|
public VMTemplateStoragePoolVO findByHostTemplate(Long hostId, Long templateId, String configuration) {
|
||||||
List<VMTemplateStoragePoolVO> result = listByHostTemplate(hostId, templateId);
|
List<VMTemplateStoragePoolVO> result = listByHostTemplate(hostId, templateId, configuration);
|
||||||
return (result.size() == 0) ? null : result.get(1);
|
return (result.size() == 0) ? null : result.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -30,6 +30,7 @@ import javax.annotation.PostConstruct;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
|
import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
|
||||||
|
import com.cloud.storage.ImageStore;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
@ -382,13 +383,25 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
|
|||||||
|
|
||||||
List<UserVmDetailVO> details = new ArrayList<UserVmDetailVO>();
|
List<UserVmDetailVO> details = new ArrayList<UserVmDetailVO>();
|
||||||
for (Map.Entry<String, String> entry : detailsStr.entrySet()) {
|
for (Map.Entry<String, String> entry : detailsStr.entrySet()) {
|
||||||
boolean display = visibilityMap.getOrDefault(entry.getKey(), true);
|
boolean display = visibilityMap.getOrDefault(entry.getKey(), true) && displayOVFDetails(entry.getKey());
|
||||||
details.add(new UserVmDetailVO(vm.getId(), entry.getKey(), entry.getValue(), display));
|
details.add(new UserVmDetailVO(vm.getId(), entry.getKey(), entry.getValue(), display));
|
||||||
}
|
}
|
||||||
|
|
||||||
_detailsDao.saveDetails(details);
|
_detailsDao.saveDetails(details);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Do not display VM properties parsed from OVF, handled internally
|
||||||
|
*/
|
||||||
|
private boolean displayOVFDetails(String key) {
|
||||||
|
if (key.startsWith(ImageStore.ACS_PROPERTY_PREFIX) || key.startsWith(ImageStore.OVF_HARDWARE_ITEM_PREFIX) ||
|
||||||
|
key.startsWith(ImageStore.OVF_HARDWARE_CONFIGURATION_PREFIX) || key.startsWith(ImageStore.DISK_DEFINITION_PREFIX) ||
|
||||||
|
key.startsWith(ImageStore.REQUIRED_NETWORK_PREFIX) || key.startsWith(ImageStore.OVF_EULA_SECTION_PREFIX)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Long> listPodIdsHavingVmsforAccount(long zoneId, long accountId) {
|
public List<Long> listPodIdsHavingVmsforAccount(long zoneId, long accountId) {
|
||||||
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
||||||
|
|||||||
@ -293,7 +293,6 @@
|
|||||||
<bean id="backupDaoImpl" class="org.apache.cloudstack.backup.dao.BackupDaoImpl" />
|
<bean id="backupDaoImpl" class="org.apache.cloudstack.backup.dao.BackupDaoImpl" />
|
||||||
<bean id="directDownloadCertificateDaoImpl" class="org.apache.cloudstack.direct.download.DirectDownloadCertificateDaoImpl" />
|
<bean id="directDownloadCertificateDaoImpl" class="org.apache.cloudstack.direct.download.DirectDownloadCertificateDaoImpl" />
|
||||||
<bean id="directDownloadCertificateHostMapDaoImpl" class="org.apache.cloudstack.direct.download.DirectDownloadCertificateHostMapDaoImpl" />
|
<bean id="directDownloadCertificateHostMapDaoImpl" class="org.apache.cloudstack.direct.download.DirectDownloadCertificateHostMapDaoImpl" />
|
||||||
<bean id="templateOVFPropertiesDaoImpl" class="com.cloud.storage.dao.TemplateOVFPropertiesDaoImpl" />
|
|
||||||
<bean id="routerHealthCheckResultsDaoImpl" class="com.cloud.network.dao.RouterHealthCheckResultDaoImpl" />
|
<bean id="routerHealthCheckResultsDaoImpl" class="com.cloud.network.dao.RouterHealthCheckResultDaoImpl" />
|
||||||
<bean id="VsphereStoragePolicyDaoImpl" class="com.cloud.dc.dao.VsphereStoragePolicyDaoImpl" />
|
<bean id="VsphereStoragePolicyDaoImpl" class="com.cloud.dc.dao.VsphereStoragePolicyDaoImpl" />
|
||||||
</beans>
|
</beans>
|
||||||
|
|||||||
@ -260,6 +260,218 @@ CREATE VIEW `cloud`.`storage_pool_view` AS
|
|||||||
LEFT JOIN `async_job` ON (((`async_job`.`instance_id` = `storage_pool`.`id`)
|
LEFT JOIN `async_job` ON (((`async_job`.`instance_id` = `storage_pool`.`id`)
|
||||||
AND (`async_job`.`instance_type` = 'StoragePool')
|
AND (`async_job`.`instance_type` = 'StoragePool')
|
||||||
AND (`async_job`.`job_status` = 0))));
|
AND (`async_job`.`job_status` = 0))));
|
||||||
|
-- Add passthrough instruction for appliance deployments
|
||||||
|
ALTER TABLE `cloud`.`vm_template` ADD COLUMN `deploy_as_is` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'True if the template should be deployed with disks and networks as defined by OVF';
|
||||||
|
|
||||||
|
-- Extend the template details value field
|
||||||
|
ALTER TABLE `cloud`.`vm_template_details` MODIFY COLUMN `value` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
|
||||||
|
|
||||||
|
-- Changes to template_view for both deploying multidisk OVA/vApp as is
|
||||||
|
DROP VIEW IF EXISTS `cloud`.`template_view`;
|
||||||
|
CREATE VIEW `cloud`.`template_view` AS
|
||||||
|
SELECT
|
||||||
|
`vm_template`.`id` AS `id`,
|
||||||
|
`vm_template`.`uuid` AS `uuid`,
|
||||||
|
`vm_template`.`unique_name` AS `unique_name`,
|
||||||
|
`vm_template`.`name` AS `name`,
|
||||||
|
`vm_template`.`public` AS `public`,
|
||||||
|
`vm_template`.`featured` AS `featured`,
|
||||||
|
`vm_template`.`type` AS `type`,
|
||||||
|
`vm_template`.`hvm` AS `hvm`,
|
||||||
|
`vm_template`.`bits` AS `bits`,
|
||||||
|
`vm_template`.`url` AS `url`,
|
||||||
|
`vm_template`.`format` AS `format`,
|
||||||
|
`vm_template`.`created` AS `created`,
|
||||||
|
`vm_template`.`checksum` AS `checksum`,
|
||||||
|
`vm_template`.`display_text` AS `display_text`,
|
||||||
|
`vm_template`.`enable_password` AS `enable_password`,
|
||||||
|
`vm_template`.`dynamically_scalable` AS `dynamically_scalable`,
|
||||||
|
`vm_template`.`state` AS `template_state`,
|
||||||
|
`vm_template`.`guest_os_id` AS `guest_os_id`,
|
||||||
|
`guest_os`.`uuid` AS `guest_os_uuid`,
|
||||||
|
`guest_os`.`display_name` AS `guest_os_name`,
|
||||||
|
`vm_template`.`bootable` AS `bootable`,
|
||||||
|
`vm_template`.`prepopulate` AS `prepopulate`,
|
||||||
|
`vm_template`.`cross_zones` AS `cross_zones`,
|
||||||
|
`vm_template`.`hypervisor_type` AS `hypervisor_type`,
|
||||||
|
`vm_template`.`extractable` AS `extractable`,
|
||||||
|
`vm_template`.`template_tag` AS `template_tag`,
|
||||||
|
`vm_template`.`sort_key` AS `sort_key`,
|
||||||
|
`vm_template`.`removed` AS `removed`,
|
||||||
|
`vm_template`.`enable_sshkey` AS `enable_sshkey`,
|
||||||
|
`parent_template`.`id` AS `parent_template_id`,
|
||||||
|
`parent_template`.`uuid` AS `parent_template_uuid`,
|
||||||
|
`source_template`.`id` AS `source_template_id`,
|
||||||
|
`source_template`.`uuid` AS `source_template_uuid`,
|
||||||
|
`account`.`id` AS `account_id`,
|
||||||
|
`account`.`uuid` AS `account_uuid`,
|
||||||
|
`account`.`account_name` AS `account_name`,
|
||||||
|
`account`.`type` AS `account_type`,
|
||||||
|
`domain`.`id` AS `domain_id`,
|
||||||
|
`domain`.`uuid` AS `domain_uuid`,
|
||||||
|
`domain`.`name` AS `domain_name`,
|
||||||
|
`domain`.`path` AS `domain_path`,
|
||||||
|
`projects`.`id` AS `project_id`,
|
||||||
|
`projects`.`uuid` AS `project_uuid`,
|
||||||
|
`projects`.`name` AS `project_name`,
|
||||||
|
`data_center`.`id` AS `data_center_id`,
|
||||||
|
`data_center`.`uuid` AS `data_center_uuid`,
|
||||||
|
`data_center`.`name` AS `data_center_name`,
|
||||||
|
`launch_permission`.`account_id` AS `lp_account_id`,
|
||||||
|
`template_store_ref`.`store_id` AS `store_id`,
|
||||||
|
`image_store`.`scope` AS `store_scope`,
|
||||||
|
`template_store_ref`.`state` AS `state`,
|
||||||
|
`template_store_ref`.`download_state` AS `download_state`,
|
||||||
|
`template_store_ref`.`download_pct` AS `download_pct`,
|
||||||
|
`template_store_ref`.`error_str` AS `error_str`,
|
||||||
|
`template_store_ref`.`size` AS `size`,
|
||||||
|
`template_store_ref`.physical_size AS `physical_size`,
|
||||||
|
`template_store_ref`.`destroyed` AS `destroyed`,
|
||||||
|
`template_store_ref`.`created` AS `created_on_store`,
|
||||||
|
`vm_template_details`.`name` AS `detail_name`,
|
||||||
|
`vm_template_details`.`value` AS `detail_value`,
|
||||||
|
`resource_tags`.`id` AS `tag_id`,
|
||||||
|
`resource_tags`.`uuid` AS `tag_uuid`,
|
||||||
|
`resource_tags`.`key` AS `tag_key`,
|
||||||
|
`resource_tags`.`value` AS `tag_value`,
|
||||||
|
`resource_tags`.`domain_id` AS `tag_domain_id`,
|
||||||
|
`domain`.`uuid` AS `tag_domain_uuid`,
|
||||||
|
`domain`.`name` AS `tag_domain_name`,
|
||||||
|
`resource_tags`.`account_id` AS `tag_account_id`,
|
||||||
|
`account`.`account_name` AS `tag_account_name`,
|
||||||
|
`resource_tags`.`resource_id` AS `tag_resource_id`,
|
||||||
|
`resource_tags`.`resource_uuid` AS `tag_resource_uuid`,
|
||||||
|
`resource_tags`.`resource_type` AS `tag_resource_type`,
|
||||||
|
`resource_tags`.`customer` AS `tag_customer`,
|
||||||
|
CONCAT(`vm_template`.`id`,
|
||||||
|
'_',
|
||||||
|
IFNULL(`data_center`.`id`, 0)) AS `temp_zone_pair`,
|
||||||
|
`vm_template`.`direct_download` AS `direct_download`,
|
||||||
|
`vm_template`.`deploy_as_is` AS `deploy_as_is`
|
||||||
|
FROM
|
||||||
|
(((((((((((((`vm_template`
|
||||||
|
JOIN `guest_os` ON ((`guest_os`.`id` = `vm_template`.`guest_os_id`)))
|
||||||
|
JOIN `account` ON ((`account`.`id` = `vm_template`.`account_id`)))
|
||||||
|
JOIN `domain` ON ((`domain`.`id` = `account`.`domain_id`)))
|
||||||
|
LEFT JOIN `projects` ON ((`projects`.`project_account_id` = `account`.`id`)))
|
||||||
|
LEFT JOIN `vm_template_details` ON ((`vm_template_details`.`template_id` = `vm_template`.`id`)))
|
||||||
|
LEFT JOIN `vm_template` `source_template` ON ((`source_template`.`id` = `vm_template`.`source_template_id`)))
|
||||||
|
LEFT JOIN `template_store_ref` ON (((`template_store_ref`.`template_id` = `vm_template`.`id`)
|
||||||
|
AND (`template_store_ref`.`store_role` = 'Image')
|
||||||
|
AND (`template_store_ref`.`destroyed` = 0))))
|
||||||
|
LEFT JOIN `vm_template` `parent_template` ON ((`parent_template`.`id` = `vm_template`.`parent_template_id`)))
|
||||||
|
LEFT JOIN `image_store` ON ((ISNULL(`image_store`.`removed`)
|
||||||
|
AND (`template_store_ref`.`store_id` IS NOT NULL)
|
||||||
|
AND (`image_store`.`id` = `template_store_ref`.`store_id`))))
|
||||||
|
LEFT JOIN `template_zone_ref` ON (((`template_zone_ref`.`template_id` = `vm_template`.`id`)
|
||||||
|
AND ISNULL(`template_store_ref`.`store_id`)
|
||||||
|
AND ISNULL(`template_zone_ref`.`removed`))))
|
||||||
|
LEFT JOIN `data_center` ON (((`image_store`.`data_center_id` = `data_center`.`id`)
|
||||||
|
OR (`template_zone_ref`.`zone_id` = `data_center`.`id`))))
|
||||||
|
LEFT JOIN `launch_permission` ON ((`launch_permission`.`template_id` = `vm_template`.`id`)))
|
||||||
|
LEFT JOIN `resource_tags` ON (((`resource_tags`.`resource_id` = `vm_template`.`id`)
|
||||||
|
AND ((`resource_tags`.`resource_type` = 'Template')
|
||||||
|
OR (`resource_tags`.`resource_type` = 'ISO')))));
|
||||||
|
|
||||||
|
-- Add mincpu, maxcpu, minmemory and maxmemory to the view supporting constrained offerings
|
||||||
|
DROP VIEW IF EXISTS `cloud`.`service_offering_view`;
|
||||||
|
CREATE VIEW `cloud`.`service_offering_view` AS
|
||||||
|
SELECT
|
||||||
|
`service_offering`.`id` AS `id`,
|
||||||
|
`disk_offering`.`uuid` AS `uuid`,
|
||||||
|
`disk_offering`.`name` AS `name`,
|
||||||
|
`disk_offering`.`display_text` AS `display_text`,
|
||||||
|
`disk_offering`.`provisioning_type` AS `provisioning_type`,
|
||||||
|
`disk_offering`.`created` AS `created`,
|
||||||
|
`disk_offering`.`tags` AS `tags`,
|
||||||
|
`disk_offering`.`removed` AS `removed`,
|
||||||
|
`disk_offering`.`use_local_storage` AS `use_local_storage`,
|
||||||
|
`disk_offering`.`system_use` AS `system_use`,
|
||||||
|
`disk_offering`.`customized_iops` AS `customized_iops`,
|
||||||
|
`disk_offering`.`min_iops` AS `min_iops`,
|
||||||
|
`disk_offering`.`max_iops` AS `max_iops`,
|
||||||
|
`disk_offering`.`hv_ss_reserve` AS `hv_ss_reserve`,
|
||||||
|
`disk_offering`.`bytes_read_rate` AS `bytes_read_rate`,
|
||||||
|
`disk_offering`.`bytes_read_rate_max` AS `bytes_read_rate_max`,
|
||||||
|
`disk_offering`.`bytes_read_rate_max_length` AS `bytes_read_rate_max_length`,
|
||||||
|
`disk_offering`.`bytes_write_rate` AS `bytes_write_rate`,
|
||||||
|
`disk_offering`.`bytes_write_rate_max` AS `bytes_write_rate_max`,
|
||||||
|
`disk_offering`.`bytes_write_rate_max_length` AS `bytes_write_rate_max_length`,
|
||||||
|
`disk_offering`.`iops_read_rate` AS `iops_read_rate`,
|
||||||
|
`disk_offering`.`iops_read_rate_max` AS `iops_read_rate_max`,
|
||||||
|
`disk_offering`.`iops_read_rate_max_length` AS `iops_read_rate_max_length`,
|
||||||
|
`disk_offering`.`iops_write_rate` AS `iops_write_rate`,
|
||||||
|
`disk_offering`.`iops_write_rate_max` AS `iops_write_rate_max`,
|
||||||
|
`disk_offering`.`iops_write_rate_max_length` AS `iops_write_rate_max_length`,
|
||||||
|
`disk_offering`.`cache_mode` AS `cache_mode`,
|
||||||
|
`service_offering`.`cpu` AS `cpu`,
|
||||||
|
`service_offering`.`speed` AS `speed`,
|
||||||
|
`service_offering`.`ram_size` AS `ram_size`,
|
||||||
|
`service_offering`.`nw_rate` AS `nw_rate`,
|
||||||
|
`service_offering`.`mc_rate` AS `mc_rate`,
|
||||||
|
`service_offering`.`ha_enabled` AS `ha_enabled`,
|
||||||
|
`service_offering`.`limit_cpu_use` AS `limit_cpu_use`,
|
||||||
|
`service_offering`.`host_tag` AS `host_tag`,
|
||||||
|
`service_offering`.`default_use` AS `default_use`,
|
||||||
|
`service_offering`.`vm_type` AS `vm_type`,
|
||||||
|
`service_offering`.`sort_key` AS `sort_key`,
|
||||||
|
`service_offering`.`is_volatile` AS `is_volatile`,
|
||||||
|
`service_offering`.`deployment_planner` AS `deployment_planner`,
|
||||||
|
GROUP_CONCAT(DISTINCT(domain.id)) AS domain_id,
|
||||||
|
GROUP_CONCAT(DISTINCT(domain.uuid)) AS domain_uuid,
|
||||||
|
GROUP_CONCAT(DISTINCT(domain.name)) AS domain_name,
|
||||||
|
GROUP_CONCAT(DISTINCT(domain.path)) AS domain_path,
|
||||||
|
GROUP_CONCAT(DISTINCT(zone.id)) AS zone_id,
|
||||||
|
GROUP_CONCAT(DISTINCT(zone.uuid)) AS zone_uuid,
|
||||||
|
GROUP_CONCAT(DISTINCT(zone.name)) AS zone_name,
|
||||||
|
IFNULL(`min_compute_details`.`value`, `cpu`) AS min_cpu,
|
||||||
|
IFNULL(`max_compute_details`.`value`, `cpu`) AS max_cpu,
|
||||||
|
IFNULL(`min_memory_details`.`value`, `ram_size`) AS min_memory,
|
||||||
|
IFNULL(`max_memory_details`.`value`, `ram_size`) AS max_memory
|
||||||
|
FROM
|
||||||
|
`cloud`.`service_offering`
|
||||||
|
INNER JOIN
|
||||||
|
`cloud`.`disk_offering_view` AS `disk_offering` ON service_offering.id = disk_offering.id
|
||||||
|
LEFT JOIN
|
||||||
|
`cloud`.`service_offering_details` AS `domain_details` ON `domain_details`.`service_offering_id` = `disk_offering`.`id` AND `domain_details`.`name`='domainid'
|
||||||
|
LEFT JOIN
|
||||||
|
`cloud`.`domain` AS `domain` ON FIND_IN_SET(`domain`.`id`, `domain_details`.`value`)
|
||||||
|
LEFT JOIN
|
||||||
|
`cloud`.`service_offering_details` AS `zone_details` ON `zone_details`.`service_offering_id` = `disk_offering`.`id` AND `zone_details`.`name`='zoneid'
|
||||||
|
LEFT JOIN
|
||||||
|
`cloud`.`data_center` AS `zone` ON FIND_IN_SET(`zone`.`id`, `zone_details`.`value`)
|
||||||
|
LEFT JOIN
|
||||||
|
`cloud`.`service_offering_details` AS `min_compute_details` ON `min_compute_details`.`service_offering_id` = `disk_offering`.`id`
|
||||||
|
AND `min_compute_details`.`name` = 'mincpunumber'
|
||||||
|
LEFT JOIN
|
||||||
|
`cloud`.`service_offering_details` AS `max_compute_details` ON `max_compute_details`.`service_offering_id` = `disk_offering`.`id`
|
||||||
|
AND `max_compute_details`.`name` = 'maxcpunumber'
|
||||||
|
LEFT JOIN
|
||||||
|
`cloud`.`service_offering_details` AS `min_memory_details` ON `min_memory_details`.`service_offering_id` = `disk_offering`.`id`
|
||||||
|
AND `min_memory_details`.`name` = 'minmemory'
|
||||||
|
LEFT JOIN
|
||||||
|
`cloud`.`service_offering_details` AS `max_memory_details` ON `max_memory_details`.`service_offering_id` = `disk_offering`.`id`
|
||||||
|
AND `max_memory_details`.`name` = 'maxmemory'
|
||||||
|
WHERE
|
||||||
|
`disk_offering`.`state`='Active'
|
||||||
|
GROUP BY
|
||||||
|
`service_offering`.`id`;
|
||||||
|
|
||||||
|
ALTER TABLE `cloud`.`template_spool_ref`
|
||||||
|
DROP FOREIGN KEY `fk_template_spool_ref__template_id`;
|
||||||
|
|
||||||
|
ALTER TABLE `cloud`.`template_spool_ref`
|
||||||
|
ADD COLUMN `deployment_option` VARCHAR(255) NULL DEFAULT NULL AFTER `updated`,
|
||||||
|
ADD INDEX `fk_template_spool_ref__template_id_idx` (`template_id` ASC),
|
||||||
|
ADD UNIQUE INDEX `index_template_spool_configuration` (`pool_id` ASC, `template_id` ASC, `deployment_option` ASC),
|
||||||
|
DROP INDEX `i_template_spool_ref__template_id__pool_id` ;
|
||||||
|
|
||||||
|
ALTER TABLE `cloud`.`template_spool_ref`
|
||||||
|
ADD CONSTRAINT `fk_template_spool_ref__template_id`
|
||||||
|
FOREIGN KEY (`template_id`)
|
||||||
|
REFERENCES `cloud`.`vm_template` (`id`)
|
||||||
|
ON DELETE NO ACTION
|
||||||
|
ON UPDATE NO ACTION;
|
||||||
|
|
||||||
ALTER TABLE `cloud`.`image_store` ADD COLUMN `readonly` boolean DEFAULT false COMMENT 'defines status of image store';
|
ALTER TABLE `cloud`.`image_store` ADD COLUMN `readonly` boolean DEFAULT false COMMENT 'defines status of image store';
|
||||||
|
|
||||||
|
|||||||
@ -291,7 +291,7 @@ public class StorageCacheManagerImpl implements StorageCacheManager, Manager {
|
|||||||
|
|
||||||
if (st == ObjectInDataStoreStateMachine.State.Ready) {
|
if (st == ObjectInDataStoreStateMachine.State.Ready) {
|
||||||
s_logger.debug("there is already one in the cache store");
|
s_logger.debug("there is already one in the cache store");
|
||||||
DataObject dataObj = objectInStoreMgr.get(data, store);
|
DataObject dataObj = objectInStoreMgr.get(data, store, null);
|
||||||
dataObj.incRefCount();
|
dataObj.incRefCount();
|
||||||
existingDataObj = dataObj;
|
existingDataObj = dataObj;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -195,7 +195,7 @@ public class KvmNonManagedStorageDataMotionStrategy extends StorageSystemDataMot
|
|||||||
@Override
|
@Override
|
||||||
protected void copyTemplateToTargetFilesystemStorageIfNeeded(VolumeInfo srcVolumeInfo, StoragePool srcStoragePool, DataStore destDataStore, StoragePool destStoragePool,
|
protected void copyTemplateToTargetFilesystemStorageIfNeeded(VolumeInfo srcVolumeInfo, StoragePool srcStoragePool, DataStore destDataStore, StoragePool destStoragePool,
|
||||||
Host destHost) {
|
Host destHost) {
|
||||||
VMTemplateStoragePoolVO sourceVolumeTemplateStoragePoolVO = vmTemplatePoolDao.findByPoolTemplate(destStoragePool.getId(), srcVolumeInfo.getTemplateId());
|
VMTemplateStoragePoolVO sourceVolumeTemplateStoragePoolVO = vmTemplatePoolDao.findByPoolTemplate(destStoragePool.getId(), srcVolumeInfo.getTemplateId(), null);
|
||||||
if (sourceVolumeTemplateStoragePoolVO == null && destStoragePool.getPoolType() == StoragePoolType.Filesystem) {
|
if (sourceVolumeTemplateStoragePoolVO == null && destStoragePool.getPoolType() == StoragePoolType.Filesystem) {
|
||||||
DataStore sourceTemplateDataStore = dataStoreManagerImpl.getRandomImageStore(srcVolumeInfo.getDataCenterId());
|
DataStore sourceTemplateDataStore = dataStoreManagerImpl.getRandomImageStore(srcVolumeInfo.getDataCenterId());
|
||||||
if (sourceTemplateDataStore != null) {
|
if (sourceTemplateDataStore != null) {
|
||||||
@ -220,8 +220,8 @@ public class KvmNonManagedStorageDataMotionStrategy extends StorageSystemDataMot
|
|||||||
* Update the template reference on table "template_spool_ref" (VMTemplateStoragePoolVO).
|
* Update the template reference on table "template_spool_ref" (VMTemplateStoragePoolVO).
|
||||||
*/
|
*/
|
||||||
protected void updateTemplateReferenceIfSuccessfulCopy(VolumeInfo srcVolumeInfo, StoragePool srcStoragePool, TemplateInfo destTemplateInfo, DataStore destDataStore) {
|
protected void updateTemplateReferenceIfSuccessfulCopy(VolumeInfo srcVolumeInfo, StoragePool srcStoragePool, TemplateInfo destTemplateInfo, DataStore destDataStore) {
|
||||||
VMTemplateStoragePoolVO srcVolumeTemplateStoragePoolVO = vmTemplatePoolDao.findByPoolTemplate(srcStoragePool.getId(), srcVolumeInfo.getTemplateId());
|
VMTemplateStoragePoolVO srcVolumeTemplateStoragePoolVO = vmTemplatePoolDao.findByPoolTemplate(srcStoragePool.getId(), srcVolumeInfo.getTemplateId(), null);
|
||||||
VMTemplateStoragePoolVO destVolumeTemplateStoragePoolVO = new VMTemplateStoragePoolVO(destDataStore.getId(), srcVolumeInfo.getTemplateId());
|
VMTemplateStoragePoolVO destVolumeTemplateStoragePoolVO = new VMTemplateStoragePoolVO(destDataStore.getId(), srcVolumeInfo.getTemplateId(), null);
|
||||||
destVolumeTemplateStoragePoolVO.setDownloadPercent(100);
|
destVolumeTemplateStoragePoolVO.setDownloadPercent(100);
|
||||||
destVolumeTemplateStoragePoolVO.setDownloadState(VMTemplateStorageResourceAssoc.Status.DOWNLOADED);
|
destVolumeTemplateStoragePoolVO.setDownloadState(VMTemplateStorageResourceAssoc.Status.DOWNLOADED);
|
||||||
destVolumeTemplateStoragePoolVO.setState(ObjectInDataStoreStateMachine.State.Ready);
|
destVolumeTemplateStoragePoolVO.setState(ObjectInDataStoreStateMachine.State.Ready);
|
||||||
|
|||||||
@ -1710,7 +1710,7 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
|
|||||||
* Return expected MigrationOptions for a linked clone volume live storage migration
|
* Return expected MigrationOptions for a linked clone volume live storage migration
|
||||||
*/
|
*/
|
||||||
protected MigrationOptions createLinkedCloneMigrationOptions(VolumeInfo srcVolumeInfo, VolumeInfo destVolumeInfo, String srcVolumeBackingFile, String srcPoolUuid, Storage.StoragePoolType srcPoolType) {
|
protected MigrationOptions createLinkedCloneMigrationOptions(VolumeInfo srcVolumeInfo, VolumeInfo destVolumeInfo, String srcVolumeBackingFile, String srcPoolUuid, Storage.StoragePoolType srcPoolType) {
|
||||||
VMTemplateStoragePoolVO ref = templatePoolDao.findByPoolTemplate(destVolumeInfo.getPoolId(), srcVolumeInfo.getTemplateId());
|
VMTemplateStoragePoolVO ref = templatePoolDao.findByPoolTemplate(destVolumeInfo.getPoolId(), srcVolumeInfo.getTemplateId(), null);
|
||||||
boolean updateBackingFileReference = ref == null;
|
boolean updateBackingFileReference = ref == null;
|
||||||
String backingFile = ref != null ? ref.getInstallPath() : srcVolumeBackingFile;
|
String backingFile = ref != null ? ref.getInstallPath() : srcVolumeBackingFile;
|
||||||
return new MigrationOptions(srcPoolUuid, srcPoolType, backingFile, updateBackingFileReference);
|
return new MigrationOptions(srcPoolUuid, srcPoolType, backingFile, updateBackingFileReference);
|
||||||
@ -1983,7 +1983,7 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
|
|||||||
srcVolumeInfo.getTemplateId() != null && srcVolumeInfo.getPoolId() != null) {
|
srcVolumeInfo.getTemplateId() != null && srcVolumeInfo.getPoolId() != null) {
|
||||||
VMTemplateVO template = _vmTemplateDao.findById(srcVolumeInfo.getTemplateId());
|
VMTemplateVO template = _vmTemplateDao.findById(srcVolumeInfo.getTemplateId());
|
||||||
if (template.getFormat() != null && template.getFormat() != Storage.ImageFormat.ISO) {
|
if (template.getFormat() != null && template.getFormat() != Storage.ImageFormat.ISO) {
|
||||||
VMTemplateStoragePoolVO ref = templatePoolDao.findByPoolTemplate(srcVolumeInfo.getPoolId(), srcVolumeInfo.getTemplateId());
|
VMTemplateStoragePoolVO ref = templatePoolDao.findByPoolTemplate(srcVolumeInfo.getPoolId(), srcVolumeInfo.getTemplateId(), null);
|
||||||
return ref != null ? ref.getInstallPath() : null;
|
return ref != null ? ref.getInstallPath() : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2157,8 +2157,8 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
|
|||||||
* Update reference on template_spool_ref table of copied template to destination storage
|
* Update reference on template_spool_ref table of copied template to destination storage
|
||||||
*/
|
*/
|
||||||
protected void updateCopiedTemplateReference(VolumeInfo srcVolumeInfo, VolumeInfo destVolumeInfo) {
|
protected void updateCopiedTemplateReference(VolumeInfo srcVolumeInfo, VolumeInfo destVolumeInfo) {
|
||||||
VMTemplateStoragePoolVO ref = templatePoolDao.findByPoolTemplate(srcVolumeInfo.getPoolId(), srcVolumeInfo.getTemplateId());
|
VMTemplateStoragePoolVO ref = templatePoolDao.findByPoolTemplate(srcVolumeInfo.getPoolId(), srcVolumeInfo.getTemplateId(), null);
|
||||||
VMTemplateStoragePoolVO newRef = new VMTemplateStoragePoolVO(destVolumeInfo.getPoolId(), ref.getTemplateId());
|
VMTemplateStoragePoolVO newRef = new VMTemplateStoragePoolVO(destVolumeInfo.getPoolId(), ref.getTemplateId(), null);
|
||||||
newRef.setDownloadPercent(100);
|
newRef.setDownloadPercent(100);
|
||||||
newRef.setDownloadState(VMTemplateStorageResourceAssoc.Status.DOWNLOADED);
|
newRef.setDownloadState(VMTemplateStorageResourceAssoc.Status.DOWNLOADED);
|
||||||
newRef.setState(ObjectInDataStoreStateMachine.State.Ready);
|
newRef.setState(ObjectInDataStoreStateMachine.State.Ready);
|
||||||
|
|||||||
@ -19,6 +19,7 @@
|
|||||||
package org.apache.cloudstack.storage.motion;
|
package org.apache.cloudstack.storage.motion;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.ArgumentMatchers.nullable;
|
||||||
import static org.mockito.Mockito.lenient;
|
import static org.mockito.Mockito.lenient;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@ -301,7 +302,7 @@ public class KvmNonManagedStorageSystemDataMotionTest {
|
|||||||
public void copyTemplateToTargetStorageIfNeededTestTemplateAlreadyOnTargetHost() throws AgentUnavailableException, OperationTimedoutException {
|
public void copyTemplateToTargetStorageIfNeededTestTemplateAlreadyOnTargetHost() throws AgentUnavailableException, OperationTimedoutException {
|
||||||
Answer copyCommandAnswer = Mockito.mock(Answer.class);
|
Answer copyCommandAnswer = Mockito.mock(Answer.class);
|
||||||
Mockito.lenient().when(copyCommandAnswer.getResult()).thenReturn(true);
|
Mockito.lenient().when(copyCommandAnswer.getResult()).thenReturn(true);
|
||||||
configureAndTestcopyTemplateToTargetStorageIfNeeded(new VMTemplateStoragePoolVO(0l, 0l), StoragePoolType.Filesystem, 0);
|
configureAndTestcopyTemplateToTargetStorageIfNeeded(new VMTemplateStoragePoolVO(0l, 0l, null), StoragePoolType.Filesystem, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -316,7 +317,7 @@ public class KvmNonManagedStorageSystemDataMotionTest {
|
|||||||
if (storagePoolTypeArray[i] == StoragePoolType.Filesystem) {
|
if (storagePoolTypeArray[i] == StoragePoolType.Filesystem) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
configureAndTestcopyTemplateToTargetStorageIfNeeded(new VMTemplateStoragePoolVO(0l, 0l), storagePoolTypeArray[i], 0);
|
configureAndTestcopyTemplateToTargetStorageIfNeeded(new VMTemplateStoragePoolVO(0l, 0l, null), storagePoolTypeArray[i], 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,7 +354,7 @@ public class KvmNonManagedStorageSystemDataMotionTest {
|
|||||||
Mockito.when(sourceTemplateInfo.getSize()).thenReturn(0l);
|
Mockito.when(sourceTemplateInfo.getSize()).thenReturn(0l);
|
||||||
Mockito.when(sourceTemplateInfo.getHypervisorType()).thenReturn(HypervisorType.KVM);
|
Mockito.when(sourceTemplateInfo.getHypervisorType()).thenReturn(HypervisorType.KVM);
|
||||||
|
|
||||||
Mockito.when(vmTemplatePoolDao.findByPoolTemplate(Mockito.anyLong(), Mockito.anyLong())).thenReturn(vmTemplateStoragePoolVO);
|
Mockito.when(vmTemplatePoolDao.findByPoolTemplate(Mockito.anyLong(), Mockito.anyLong(), nullable(String.class))).thenReturn(vmTemplateStoragePoolVO);
|
||||||
Mockito.when(dataStoreManagerImpl.getRandomImageStore(Mockito.anyLong())).thenReturn(sourceTemplateDataStore);
|
Mockito.when(dataStoreManagerImpl.getRandomImageStore(Mockito.anyLong())).thenReturn(sourceTemplateDataStore);
|
||||||
Mockito.when(templateDataFactory.getTemplate(Mockito.anyLong(), Mockito.eq(sourceTemplateDataStore))).thenReturn(sourceTemplateInfo);
|
Mockito.when(templateDataFactory.getTemplate(Mockito.anyLong(), Mockito.eq(sourceTemplateDataStore))).thenReturn(sourceTemplateInfo);
|
||||||
Mockito.when(templateDataFactory.getTemplate(Mockito.anyLong(), Mockito.eq(destDataStore))).thenReturn(sourceTemplateInfo);
|
Mockito.when(templateDataFactory.getTemplate(Mockito.anyLong(), Mockito.eq(destDataStore))).thenReturn(sourceTemplateInfo);
|
||||||
@ -362,7 +363,7 @@ public class KvmNonManagedStorageSystemDataMotionTest {
|
|||||||
Mockito.any(TemplateInfo.class), Mockito.any(DataStore.class));
|
Mockito.any(TemplateInfo.class), Mockito.any(DataStore.class));
|
||||||
|
|
||||||
InOrder verifyInOrder = Mockito.inOrder(vmTemplatePoolDao, dataStoreManagerImpl, templateDataFactory, kvmNonManagedStorageDataMotionStrategy);
|
InOrder verifyInOrder = Mockito.inOrder(vmTemplatePoolDao, dataStoreManagerImpl, templateDataFactory, kvmNonManagedStorageDataMotionStrategy);
|
||||||
verifyInOrder.verify(vmTemplatePoolDao, Mockito.times(1)).findByPoolTemplate(Mockito.anyLong(), Mockito.anyLong());
|
verifyInOrder.verify(vmTemplatePoolDao, Mockito.times(1)).findByPoolTemplate(Mockito.anyLong(), Mockito.anyLong(), nullable(String.class));
|
||||||
verifyInOrder.verify(dataStoreManagerImpl, Mockito.times(times)).getRandomImageStore(Mockito.anyLong());
|
verifyInOrder.verify(dataStoreManagerImpl, Mockito.times(times)).getRandomImageStore(Mockito.anyLong());
|
||||||
verifyInOrder.verify(templateDataFactory, Mockito.times(times)).getTemplate(Mockito.anyLong(), Mockito.eq(sourceTemplateDataStore));
|
verifyInOrder.verify(templateDataFactory, Mockito.times(times)).getTemplate(Mockito.anyLong(), Mockito.eq(sourceTemplateDataStore));
|
||||||
verifyInOrder.verify(templateDataFactory, Mockito.times(times)).getTemplate(Mockito.anyLong(), Mockito.eq(destDataStore));
|
verifyInOrder.verify(templateDataFactory, Mockito.times(times)).getTemplate(Mockito.anyLong(), Mockito.eq(destDataStore));
|
||||||
|
|||||||
@ -23,6 +23,9 @@ import java.util.List;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
|
import com.cloud.utils.StringUtils;
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import org.apache.cloudstack.direct.download.DirectDownloadManager;
|
import org.apache.cloudstack.direct.download.DirectDownloadManager;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||||
@ -39,13 +42,11 @@ import org.springframework.stereotype.Component;
|
|||||||
|
|
||||||
import com.cloud.host.HostVO;
|
import com.cloud.host.HostVO;
|
||||||
import com.cloud.host.dao.HostDao;
|
import com.cloud.host.dao.HostDao;
|
||||||
import com.cloud.hypervisor.Hypervisor;
|
|
||||||
import com.cloud.storage.DataStoreRole;
|
import com.cloud.storage.DataStoreRole;
|
||||||
import com.cloud.storage.VMTemplateStoragePoolVO;
|
import com.cloud.storage.VMTemplateStoragePoolVO;
|
||||||
import com.cloud.storage.VMTemplateVO;
|
import com.cloud.storage.VMTemplateVO;
|
||||||
import com.cloud.storage.dao.VMTemplateDao;
|
import com.cloud.storage.dao.VMTemplateDao;
|
||||||
import com.cloud.storage.dao.VMTemplatePoolDao;
|
import com.cloud.storage.dao.VMTemplatePoolDao;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class TemplateDataFactoryImpl implements TemplateDataFactory {
|
public class TemplateDataFactoryImpl implements TemplateDataFactory {
|
||||||
@ -65,17 +66,30 @@ public class TemplateDataFactoryImpl implements TemplateDataFactory {
|
|||||||
@Inject
|
@Inject
|
||||||
PrimaryDataStoreDao primaryDataStoreDao;
|
PrimaryDataStoreDao primaryDataStoreDao;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TemplateInfo getTemplateOnPrimaryStorage(long templateId, DataStore store, String configuration) {
|
||||||
|
VMTemplateVO templ = imageDataDao.findById(templateId);
|
||||||
|
if (store.getRole() == DataStoreRole.Primary) {
|
||||||
|
VMTemplateStoragePoolVO templatePoolVO = templatePoolDao.findByPoolTemplate(store.getId(), templateId, configuration);
|
||||||
|
if (templatePoolVO != null) {
|
||||||
|
String deployAsIsConfiguration = templatePoolVO.getDeploymentOption();
|
||||||
|
return TemplateObject.getTemplate(templ, store, deployAsIsConfiguration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TemplateInfo getTemplate(long templateId, DataStore store) {
|
public TemplateInfo getTemplate(long templateId, DataStore store) {
|
||||||
VMTemplateVO templ = imageDataDao.findById(templateId);
|
VMTemplateVO templ = imageDataDao.findById(templateId);
|
||||||
if (store == null && !templ.isDirectDownload()) {
|
if (store == null && !templ.isDirectDownload()) {
|
||||||
TemplateObject tmpl = TemplateObject.getTemplate(templ, null);
|
TemplateObject tmpl = TemplateObject.getTemplate(templ, null, null);
|
||||||
return tmpl;
|
return tmpl;
|
||||||
}
|
}
|
||||||
// verify if the given input parameters are consistent with our db data.
|
// verify if the given input parameters are consistent with our db data.
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
if (store.getRole() == DataStoreRole.Primary) {
|
if (store.getRole() == DataStoreRole.Primary) {
|
||||||
VMTemplateStoragePoolVO templatePoolVO = templatePoolDao.findByPoolTemplate(store.getId(), templateId);
|
VMTemplateStoragePoolVO templatePoolVO = templatePoolDao.findByPoolTemplate(store.getId(), templateId, null);
|
||||||
if (templatePoolVO != null) {
|
if (templatePoolVO != null) {
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
@ -94,7 +108,7 @@ public class TemplateDataFactoryImpl implements TemplateDataFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TemplateObject tmpl = TemplateObject.getTemplate(templ, store);
|
TemplateObject tmpl = TemplateObject.getTemplate(templ, store, null);
|
||||||
return tmpl;
|
return tmpl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,8 +144,13 @@ public class TemplateDataFactoryImpl implements TemplateDataFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TemplateInfo getTemplate(DataObject obj, DataStore store) {
|
public TemplateInfo getTemplate(DataObject obj, DataStore store, String configuration) {
|
||||||
TemplateObject tmpObj = (TemplateObject)this.getTemplate(obj.getId(), store);
|
TemplateObject tmpObj;
|
||||||
|
if (StringUtils.isNotBlank(configuration)) {
|
||||||
|
tmpObj = (TemplateObject)this.getTemplateOnPrimaryStorage(obj.getId(), store, configuration);
|
||||||
|
} else {
|
||||||
|
tmpObj = (TemplateObject)this.getTemplate(obj.getId(), store);
|
||||||
|
}
|
||||||
// carry over url set in passed in data object, for copyTemplate case
|
// carry over url set in passed in data object, for copyTemplate case
|
||||||
// where url is generated on demand and not persisted in DB.
|
// where url is generated on demand and not persisted in DB.
|
||||||
// need to think of a more generic way to pass these runtime information
|
// need to think of a more generic way to pass these runtime information
|
||||||
@ -217,7 +236,7 @@ public class TemplateDataFactoryImpl implements TemplateDataFactory {
|
|||||||
if (pool == null) {
|
if (pool == null) {
|
||||||
throw new CloudRuntimeException("No storage pool found where to download template: " + templateId);
|
throw new CloudRuntimeException("No storage pool found where to download template: " + templateId);
|
||||||
}
|
}
|
||||||
VMTemplateStoragePoolVO spoolRef = templatePoolDao.findByPoolTemplate(pool, templateId);
|
VMTemplateStoragePoolVO spoolRef = templatePoolDao.findByPoolTemplate(pool, templateId, null);
|
||||||
if (spoolRef == null) {
|
if (spoolRef == null) {
|
||||||
directDownloadManager.downloadTemplate(templateId, pool, hostId);
|
directDownloadManager.downloadTemplate(templateId, pool, hostId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -204,7 +204,7 @@ public class TemplateServiceImpl implements TemplateService {
|
|||||||
// clean up already persisted template_store_ref entry in case of createTemplateCallback is never called
|
// clean up already persisted template_store_ref entry in case of createTemplateCallback is never called
|
||||||
TemplateDataStoreVO templateStoreVO = _vmTemplateStoreDao.findByStoreTemplate(store.getId(), template.getId());
|
TemplateDataStoreVO templateStoreVO = _vmTemplateStoreDao.findByStoreTemplate(store.getId(), template.getId());
|
||||||
if (templateStoreVO != null) {
|
if (templateStoreVO != null) {
|
||||||
TemplateInfo tmplObj = _templateFactory.getTemplate(template, store);
|
TemplateInfo tmplObj = _templateFactory.getTemplate(template, store, null);
|
||||||
tmplObj.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed);
|
tmplObj.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed);
|
||||||
}
|
}
|
||||||
TemplateApiResult result = new TemplateApiResult(template);
|
TemplateApiResult result = new TemplateApiResult(template);
|
||||||
@ -412,7 +412,7 @@ public class TemplateServiceImpl implements TemplateService {
|
|||||||
VirtualMachineTemplate.Event event = VirtualMachineTemplate.Event.OperationSucceeded;
|
VirtualMachineTemplate.Event event = VirtualMachineTemplate.Event.OperationSucceeded;
|
||||||
// For multi-disk OVA, check and create data disk templates
|
// For multi-disk OVA, check and create data disk templates
|
||||||
if (tmplt.getFormat().equals(ImageFormat.OVA)) {
|
if (tmplt.getFormat().equals(ImageFormat.OVA)) {
|
||||||
if (!createOvaDataDiskTemplates(_templateFactory.getTemplate(tmlpt.getId(), store))) {
|
if (!createOvaDataDiskTemplates(_templateFactory.getTemplate(tmlpt.getId(), store), tmplt.isDeployAsIs())) {
|
||||||
event = VirtualMachineTemplate.Event.OperationFailed;
|
event = VirtualMachineTemplate.Event.OperationFailed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -710,7 +710,7 @@ public class TemplateServiceImpl implements TemplateService {
|
|||||||
|
|
||||||
// For multi-disk OVA, check and create data disk templates
|
// For multi-disk OVA, check and create data disk templates
|
||||||
if (template.getFormat().equals(ImageFormat.OVA)) {
|
if (template.getFormat().equals(ImageFormat.OVA)) {
|
||||||
if (!createOvaDataDiskTemplates(template)) {
|
if (!createOvaDataDiskTemplates(template, template.isDeployAsIs())) {
|
||||||
template.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed);
|
template.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed);
|
||||||
result.setResult(callbackResult.getResult());
|
result.setResult(callbackResult.getResult());
|
||||||
if (parentCallback != null) {
|
if (parentCallback != null) {
|
||||||
@ -737,12 +737,18 @@ public class TemplateServiceImpl implements TemplateService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean createOvaDataDiskTemplates(TemplateInfo parentTemplate) {
|
public List<DatadiskTO> getTemplateDatadisksOnImageStore(TemplateInfo templateInfo, String configurationId) {
|
||||||
|
ImageStoreEntity tmpltStore = (ImageStoreEntity)templateInfo.getDataStore();
|
||||||
|
return tmpltStore.getDataDiskTemplates(templateInfo, configurationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean createOvaDataDiskTemplates(TemplateInfo parentTemplate, boolean deployAsIs) {
|
||||||
try {
|
try {
|
||||||
// Get Datadisk template (if any) for OVA
|
// Get Datadisk template (if any) for OVA
|
||||||
List<DatadiskTO> dataDiskTemplates = new ArrayList<DatadiskTO>();
|
List<DatadiskTO> dataDiskTemplates = new ArrayList<DatadiskTO>();
|
||||||
ImageStoreEntity tmpltStore = (ImageStoreEntity)parentTemplate.getDataStore();
|
ImageStoreEntity tmpltStore = (ImageStoreEntity)parentTemplate.getDataStore();
|
||||||
dataDiskTemplates = tmpltStore.getDataDiskTemplates(parentTemplate);
|
dataDiskTemplates = tmpltStore.getDataDiskTemplates(parentTemplate, null);
|
||||||
int diskCount = 0;
|
int diskCount = 0;
|
||||||
VMTemplateVO templateVO = _templateDao.findById(parentTemplate.getId());
|
VMTemplateVO templateVO = _templateDao.findById(parentTemplate.getId());
|
||||||
_templateDao.loadDetails(templateVO);
|
_templateDao.loadDetails(templateVO);
|
||||||
@ -754,7 +760,9 @@ public class TemplateServiceImpl implements TemplateService {
|
|||||||
details = new HashMap<>();
|
details = new HashMap<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (DatadiskTO diskTemplate : dataDiskTemplates) {
|
for (DatadiskTO diskTemplate : dataDiskTemplates) {
|
||||||
|
if (!deployAsIs) {
|
||||||
if (!diskTemplate.isBootable()) {
|
if (!diskTemplate.isBootable()) {
|
||||||
createChildDataDiskTemplate(diskTemplate, templateVO, parentTemplate, imageStore, diskCount++);
|
createChildDataDiskTemplate(diskTemplate, templateVO, parentTemplate, imageStore, diskCount++);
|
||||||
if (!diskTemplate.isIso() && Strings.isNullOrEmpty(details.get(VmDetailConstants.DATA_DISK_CONTROLLER))){
|
if (!diskTemplate.isIso() && Strings.isNullOrEmpty(details.get(VmDetailConstants.DATA_DISK_CONTROLLER))){
|
||||||
@ -771,6 +779,8 @@ public class TemplateServiceImpl implements TemplateService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
templateVO.setDetails(details);
|
templateVO.setDetails(details);
|
||||||
_templateDao.saveDetails(templateVO);
|
_templateDao.saveDetails(templateVO);
|
||||||
return true;
|
return true;
|
||||||
@ -789,7 +799,7 @@ public class TemplateServiceImpl implements TemplateService {
|
|||||||
String templateName = dataDiskTemplate.isIso() ? dataDiskTemplate.getPath().substring(dataDiskTemplate.getPath().lastIndexOf(File.separator) + 1) : template.getName() + suffix + diskCount;
|
String templateName = dataDiskTemplate.isIso() ? dataDiskTemplate.getPath().substring(dataDiskTemplate.getPath().lastIndexOf(File.separator) + 1) : template.getName() + suffix + diskCount;
|
||||||
VMTemplateVO templateVO = new VMTemplateVO(templateId, templateName, format, false, false, false, ttype, template.getUrl(),
|
VMTemplateVO templateVO = new VMTemplateVO(templateId, templateName, format, false, false, false, ttype, template.getUrl(),
|
||||||
template.requiresHvm(), template.getBits(), template.getAccountId(), null, templateName, false, guestOsId, false, template.getHypervisorType(), null,
|
template.requiresHvm(), template.getBits(), template.getAccountId(), null, templateName, false, guestOsId, false, template.getHypervisorType(), null,
|
||||||
null, false, false, false);
|
null, false, false, false, false);
|
||||||
if (dataDiskTemplate.isIso()){
|
if (dataDiskTemplate.isIso()){
|
||||||
templateVO.setUniqueName(templateName);
|
templateVO.setUniqueName(templateName);
|
||||||
}
|
}
|
||||||
@ -952,7 +962,7 @@ public class TemplateServiceImpl implements TemplateService {
|
|||||||
AsyncCallFuture<TemplateApiResult> future = new AsyncCallFuture<TemplateApiResult>();
|
AsyncCallFuture<TemplateApiResult> future = new AsyncCallFuture<TemplateApiResult>();
|
||||||
// no need to create entry on template_store_ref here, since entries are already created when prepareSecondaryStorageForMigration is invoked.
|
// no need to create entry on template_store_ref here, since entries are already created when prepareSecondaryStorageForMigration is invoked.
|
||||||
// But we need to set default install path so that sync can be done in the right s3 path
|
// But we need to set default install path so that sync can be done in the right s3 path
|
||||||
TemplateInfo templateOnStore = _templateFactory.getTemplate(template, store);
|
TemplateInfo templateOnStore = _templateFactory.getTemplate(template, store, null);
|
||||||
String installPath =
|
String installPath =
|
||||||
TemplateConstants.DEFAULT_TMPLT_ROOT_DIR + "/" + TemplateConstants.DEFAULT_TMPLT_FIRST_LEVEL_DIR + template.getAccountId() + "/" + template.getId() + "/" +
|
TemplateConstants.DEFAULT_TMPLT_ROOT_DIR + "/" + TemplateConstants.DEFAULT_TMPLT_FIRST_LEVEL_DIR + template.getAccountId() + "/" + template.getId() + "/" +
|
||||||
template.getUniqueName();
|
template.getUniqueName();
|
||||||
@ -1039,7 +1049,7 @@ public class TemplateServiceImpl implements TemplateService {
|
|||||||
throw new CloudRuntimeException("No secondary VM in running state in source template zone ");
|
throw new CloudRuntimeException("No secondary VM in running state in source template zone ");
|
||||||
}
|
}
|
||||||
|
|
||||||
TemplateObject tmplForCopy = (TemplateObject)_templateFactory.getTemplate(srcTemplate, destStore);
|
TemplateObject tmplForCopy = (TemplateObject)_templateFactory.getTemplate(srcTemplate, destStore, null);
|
||||||
if (s_logger.isDebugEnabled()) {
|
if (s_logger.isDebugEnabled()) {
|
||||||
s_logger.debug("Setting source template url to " + url);
|
s_logger.debug("Setting source template url to " + url);
|
||||||
}
|
}
|
||||||
@ -1068,7 +1078,7 @@ public class TemplateServiceImpl implements TemplateService {
|
|||||||
// clean up already persisted template_store_ref entry in case of createTemplateCallback is never called
|
// clean up already persisted template_store_ref entry in case of createTemplateCallback is never called
|
||||||
TemplateDataStoreVO templateStoreVO = _vmTemplateStoreDao.findByStoreTemplate(destStore.getId(), srcTemplate.getId());
|
TemplateDataStoreVO templateStoreVO = _vmTemplateStoreDao.findByStoreTemplate(destStore.getId(), srcTemplate.getId());
|
||||||
if (templateStoreVO != null) {
|
if (templateStoreVO != null) {
|
||||||
TemplateInfo tmplObj = _templateFactory.getTemplate(srcTemplate, destStore);
|
TemplateInfo tmplObj = _templateFactory.getTemplate(srcTemplate, destStore, null);
|
||||||
tmplObj.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed);
|
tmplObj.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed);
|
||||||
}
|
}
|
||||||
TemplateApiResult res = new TemplateApiResult((TemplateObject)templateOnStore);
|
TemplateApiResult res = new TemplateApiResult((TemplateObject)templateOnStore);
|
||||||
@ -1130,7 +1140,7 @@ public class TemplateServiceImpl implements TemplateService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AsyncCallFuture<TemplateApiResult> deleteTemplateOnPrimary(TemplateInfo template, StoragePool pool) {
|
public AsyncCallFuture<TemplateApiResult> deleteTemplateOnPrimary(TemplateInfo template, StoragePool pool) {
|
||||||
TemplateObject templateObject = (TemplateObject)_templateFactory.getTemplate(template.getId(), (DataStore)pool);
|
TemplateObject templateObject = (TemplateObject)_templateFactory.getTemplateOnPrimaryStorage(template.getId(), (DataStore)pool, template.getDeployAsIsConfiguration());
|
||||||
|
|
||||||
templateObject.processEvent(ObjectInDataStoreStateMachine.Event.DestroyRequested);
|
templateObject.processEvent(ObjectInDataStoreStateMachine.Event.DestroyRequested);
|
||||||
|
|
||||||
@ -1241,7 +1251,7 @@ public class TemplateServiceImpl implements TemplateService {
|
|||||||
dataDiskTemplateOnStore = (TemplateObject)store.create(dataDiskTemplate);
|
dataDiskTemplateOnStore = (TemplateObject)store.create(dataDiskTemplate);
|
||||||
dataDiskTemplateOnStore.processEvent(ObjectInDataStoreStateMachine.Event.CreateOnlyRequested);
|
dataDiskTemplateOnStore.processEvent(ObjectInDataStoreStateMachine.Event.CreateOnlyRequested);
|
||||||
} else {
|
} else {
|
||||||
dataDiskTemplateOnStore = (TemplateObject) imageFactory.getTemplate(parentTemplate, store);
|
dataDiskTemplateOnStore = (TemplateObject) imageFactory.getTemplate(parentTemplate, store, null);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
CreateDataDiskTemplateContext<TemplateApiResult> context = new CreateDataDiskTemplateContext<TemplateApiResult>(null, dataDiskTemplateOnStore, future);
|
CreateDataDiskTemplateContext<TemplateApiResult> context = new CreateDataDiskTemplateContext<TemplateApiResult>(null, dataDiskTemplateOnStore, future);
|
||||||
|
|||||||
@ -218,8 +218,8 @@ public class ImageStoreImpl implements ImageStoreEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<DatadiskTO> getDataDiskTemplates(DataObject obj) {
|
public List<DatadiskTO> getDataDiskTemplates(DataObject obj, String configurationId) {
|
||||||
return driver.getDataDiskTemplates(obj);
|
return driver.getDataDiskTemplates(obj, configurationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -63,6 +63,7 @@ public class TemplateObject implements TemplateInfo {
|
|||||||
private DataStore dataStore;
|
private DataStore dataStore;
|
||||||
private String url;
|
private String url;
|
||||||
private String installPath; // temporarily set installPath before passing to resource for entries with empty installPath for object store migration case
|
private String installPath; // temporarily set installPath before passing to resource for entries with empty installPath for object store migration case
|
||||||
|
private String deployAsIsConfiguration; // Temporarily set
|
||||||
@Inject
|
@Inject
|
||||||
VMTemplateDao imageDao;
|
VMTemplateDao imageDao;
|
||||||
@Inject
|
@Inject
|
||||||
@ -80,8 +81,9 @@ public class TemplateObject implements TemplateInfo {
|
|||||||
this.dataStore = dataStore;
|
this.dataStore = dataStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TemplateObject getTemplate(VMTemplateVO vo, DataStore store) {
|
public static TemplateObject getTemplate(VMTemplateVO vo, DataStore store, String configuration) {
|
||||||
TemplateObject to = ComponentContext.inject(TemplateObject.class);
|
TemplateObject to = ComponentContext.inject(TemplateObject.class);
|
||||||
|
to.deployAsIsConfiguration = configuration;
|
||||||
to.configure(vo, store);
|
to.configure(vo, store);
|
||||||
return to;
|
return to;
|
||||||
}
|
}
|
||||||
@ -190,7 +192,9 @@ public class TemplateObject implements TemplateInfo {
|
|||||||
if (answer instanceof CopyCmdAnswer) {
|
if (answer instanceof CopyCmdAnswer) {
|
||||||
CopyCmdAnswer cpyAnswer = (CopyCmdAnswer)answer;
|
CopyCmdAnswer cpyAnswer = (CopyCmdAnswer)answer;
|
||||||
TemplateObjectTO newTemplate = (TemplateObjectTO)cpyAnswer.getNewData();
|
TemplateObjectTO newTemplate = (TemplateObjectTO)cpyAnswer.getNewData();
|
||||||
VMTemplateStoragePoolVO templatePoolRef = templatePoolDao.findByPoolTemplate(getDataStore().getId(), getId());
|
|
||||||
|
String deployAsIsConfiguration = newTemplate.getDeployAsIsConfiguration();
|
||||||
|
VMTemplateStoragePoolVO templatePoolRef = templatePoolDao.findByPoolTemplate(getDataStore().getId(), getId(), deployAsIsConfiguration);
|
||||||
templatePoolRef.setDownloadPercent(100);
|
templatePoolRef.setDownloadPercent(100);
|
||||||
|
|
||||||
setTemplateSizeIfNeeded(newTemplate, templatePoolRef);
|
setTemplateSizeIfNeeded(newTemplate, templatePoolRef);
|
||||||
@ -327,6 +331,11 @@ public class TemplateObject implements TemplateInfo {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDeployAsIsConfiguration() {
|
||||||
|
return deployAsIsConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataTO getTO() {
|
public DataTO getTO() {
|
||||||
DataTO to = null;
|
DataTO to = null;
|
||||||
@ -365,6 +374,14 @@ public class TemplateObject implements TemplateInfo {
|
|||||||
return this.imageVO.isDirectDownload();
|
return this.imageVO.isDirectDownload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDeployAsIs() {
|
||||||
|
if (this.imageVO == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return this.imageVO.isDeployAsIs();
|
||||||
|
}
|
||||||
|
|
||||||
public void setInstallPath(String installPath) {
|
public void setInstallPath(String installPath) {
|
||||||
this.installPath = installPath;
|
this.installPath = installPath;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -76,7 +76,7 @@ public class DataObjectManagerImpl implements DataObjectManager {
|
|||||||
s_logger.debug("waiting too long for template downloading, marked it as failed");
|
s_logger.debug("waiting too long for template downloading, marked it as failed");
|
||||||
throw new CloudRuntimeException("waiting too long for template downloading, marked it as failed");
|
throw new CloudRuntimeException("waiting too long for template downloading, marked it as failed");
|
||||||
}
|
}
|
||||||
return objectInDataStoreMgr.get(dataObj, dataStore);
|
return objectInDataStoreMgr.get(dataObj, dataStore, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
class CreateContext<T> extends AsyncRpcContext<T> {
|
class CreateContext<T> extends AsyncRpcContext<T> {
|
||||||
|
|||||||
@ -33,11 +33,11 @@ public interface ObjectInDataStoreManager {
|
|||||||
|
|
||||||
boolean deleteIfNotReady(DataObject dataObj);
|
boolean deleteIfNotReady(DataObject dataObj);
|
||||||
|
|
||||||
DataObject get(DataObject dataObj, DataStore store);
|
DataObject get(DataObject dataObj, DataStore store, String configuration);
|
||||||
|
|
||||||
boolean update(DataObject vo, Event event) throws NoTransitionException, ConcurrentOperationException;
|
boolean update(DataObject vo, Event event) throws NoTransitionException, ConcurrentOperationException;
|
||||||
|
|
||||||
DataObjectInStore findObject(long objId, DataObjectType type, long dataStoreId, DataStoreRole role);
|
DataObjectInStore findObject(long objId, DataObjectType type, long dataStoreId, DataStoreRole role, String deployAsIsConfiguration);
|
||||||
|
|
||||||
DataObjectInStore findObject(DataObject obj, DataStore store);
|
DataObjectInStore findObject(DataObject obj, DataStore store);
|
||||||
|
|
||||||
|
|||||||
@ -118,7 +118,7 @@ public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager {
|
|||||||
public DataObject create(DataObject obj, DataStore dataStore) {
|
public DataObject create(DataObject obj, DataStore dataStore) {
|
||||||
if (dataStore.getRole() == DataStoreRole.Primary) {
|
if (dataStore.getRole() == DataStoreRole.Primary) {
|
||||||
if (obj.getType() == DataObjectType.TEMPLATE) {
|
if (obj.getType() == DataObjectType.TEMPLATE) {
|
||||||
VMTemplateStoragePoolVO vo = new VMTemplateStoragePoolVO(dataStore.getId(), obj.getId());
|
VMTemplateStoragePoolVO vo = new VMTemplateStoragePoolVO(dataStore.getId(), obj.getId(), null);
|
||||||
vo = templatePoolDao.persist(vo);
|
vo = templatePoolDao.persist(vo);
|
||||||
} else if (obj.getType() == DataObjectType.SNAPSHOT) {
|
} else if (obj.getType() == DataObjectType.SNAPSHOT) {
|
||||||
SnapshotInfo snapshotInfo = (SnapshotInfo)obj;
|
SnapshotInfo snapshotInfo = (SnapshotInfo)obj;
|
||||||
@ -197,7 +197,7 @@ public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.get(obj, dataStore);
|
return this.get(obj, dataStore, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -206,7 +206,7 @@ public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager {
|
|||||||
DataStore dataStore = dataObj.getDataStore();
|
DataStore dataStore = dataObj.getDataStore();
|
||||||
if (dataStore.getRole() == DataStoreRole.Primary) {
|
if (dataStore.getRole() == DataStoreRole.Primary) {
|
||||||
if (dataObj.getType() == DataObjectType.TEMPLATE) {
|
if (dataObj.getType() == DataObjectType.TEMPLATE) {
|
||||||
VMTemplateStoragePoolVO destTmpltPool = templatePoolDao.findByPoolTemplate(dataStore.getId(), objId);
|
VMTemplateStoragePoolVO destTmpltPool = templatePoolDao.findByPoolTemplate(dataStore.getId(), objId, null);
|
||||||
if (destTmpltPool != null) {
|
if (destTmpltPool != null) {
|
||||||
return templatePoolDao.remove(destTmpltPool.getId());
|
return templatePoolDao.remove(destTmpltPool.getId());
|
||||||
} else {
|
} else {
|
||||||
@ -254,7 +254,7 @@ public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager {
|
|||||||
DataStore dataStore = dataObj.getDataStore();
|
DataStore dataStore = dataObj.getDataStore();
|
||||||
if (dataStore.getRole() == DataStoreRole.Primary) {
|
if (dataStore.getRole() == DataStoreRole.Primary) {
|
||||||
if (dataObj.getType() == DataObjectType.TEMPLATE) {
|
if (dataObj.getType() == DataObjectType.TEMPLATE) {
|
||||||
VMTemplateStoragePoolVO destTmpltPool = templatePoolDao.findByPoolTemplate(dataStore.getId(), objId);
|
VMTemplateStoragePoolVO destTmpltPool = templatePoolDao.findByPoolTemplate(dataStore.getId(), objId, null);
|
||||||
if (destTmpltPool != null && destTmpltPool.getState() != ObjectInDataStoreStateMachine.State.Ready) {
|
if (destTmpltPool != null && destTmpltPool.getState() != ObjectInDataStoreStateMachine.State.Ready) {
|
||||||
return templatePoolDao.remove(destTmpltPool.getId());
|
return templatePoolDao.remove(destTmpltPool.getId());
|
||||||
} else {
|
} else {
|
||||||
@ -333,9 +333,9 @@ public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataObject get(DataObject dataObj, DataStore store) {
|
public DataObject get(DataObject dataObj, DataStore store, String configuration) {
|
||||||
if (dataObj.getType() == DataObjectType.TEMPLATE) {
|
if (dataObj.getType() == DataObjectType.TEMPLATE) {
|
||||||
return imageFactory.getTemplate(dataObj, store);
|
return imageFactory.getTemplate(dataObj, store, configuration);
|
||||||
} else if (dataObj.getType() == DataObjectType.VOLUME) {
|
} else if (dataObj.getType() == DataObjectType.VOLUME) {
|
||||||
return volumeFactory.getVolume(dataObj, store);
|
return volumeFactory.getVolume(dataObj, store);
|
||||||
} else if (dataObj.getType() == DataObjectType.SNAPSHOT) {
|
} else if (dataObj.getType() == DataObjectType.SNAPSHOT) {
|
||||||
@ -347,11 +347,15 @@ public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataObjectInStore findObject(DataObject obj, DataStore store) {
|
public DataObjectInStore findObject(DataObject obj, DataStore store) {
|
||||||
return findObject(obj.getId(), obj.getType(), store.getId(), store.getRole());
|
String deployAsIsConfiguration = null;
|
||||||
|
if (obj.getType() == DataObjectType.TEMPLATE) {
|
||||||
|
deployAsIsConfiguration = ((TemplateInfo) obj).getDeployAsIsConfiguration();
|
||||||
|
}
|
||||||
|
return findObject(obj.getId(), obj.getType(), store.getId(), store.getRole(), deployAsIsConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataObjectInStore findObject(long objId, DataObjectType type, long dataStoreId, DataStoreRole role) {
|
public DataObjectInStore findObject(long objId, DataObjectType type, long dataStoreId, DataStoreRole role, String deployAsIsConfiguration) {
|
||||||
DataObjectInStore vo = null;
|
DataObjectInStore vo = null;
|
||||||
if (role == DataStoreRole.Image || role == DataStoreRole.ImageCache) {
|
if (role == DataStoreRole.Image || role == DataStoreRole.ImageCache) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -366,7 +370,7 @@ public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (type == DataObjectType.TEMPLATE && role == DataStoreRole.Primary) {
|
} else if (type == DataObjectType.TEMPLATE && role == DataStoreRole.Primary) {
|
||||||
vo = templatePoolDao.findByPoolTemplate(dataStoreId, objId);
|
vo = templatePoolDao.findByPoolTemplate(dataStoreId, objId, deployAsIsConfiguration);
|
||||||
} else if (type == DataObjectType.SNAPSHOT && role == DataStoreRole.Primary) {
|
} else if (type == DataObjectType.SNAPSHOT && role == DataStoreRole.Primary) {
|
||||||
vo = snapshotDataStoreDao.findByStoreSnapshot(role, dataStoreId, objId);
|
vo = snapshotDataStoreDao.findByStoreSnapshot(role, dataStoreId, objId);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.cloudstack.storage.image;
|
package org.apache.cloudstack.storage.image;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
@ -32,6 +33,21 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.storage.OVFConfigurationTO;
|
||||||
|
import com.cloud.agent.api.storage.OVFEulaSectionTO;
|
||||||
|
import com.cloud.agent.api.storage.OVFPropertyTO;
|
||||||
|
import com.cloud.agent.api.storage.OVFVirtualHardwareItemTO;
|
||||||
|
import com.cloud.agent.api.storage.OVFVirtualHardwareSectionTO;
|
||||||
|
import com.cloud.storage.ImageStore;
|
||||||
|
import com.cloud.storage.Upload;
|
||||||
|
import com.cloud.storage.VMTemplateDetailVO;
|
||||||
|
import com.cloud.utils.compression.CompressionUtil;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import org.apache.cloudstack.api.net.NetworkPrerequisiteTO;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
|
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
|
import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
|
||||||
@ -51,8 +67,6 @@ import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
|
|||||||
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO;
|
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO;
|
||||||
import org.apache.cloudstack.storage.endpoint.DefaultEndPointSelector;
|
import org.apache.cloudstack.storage.endpoint.DefaultEndPointSelector;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
import com.cloud.agent.AgentManager;
|
import com.cloud.agent.AgentManager;
|
||||||
import com.cloud.agent.api.Answer;
|
import com.cloud.agent.api.Answer;
|
||||||
@ -60,11 +74,9 @@ import com.cloud.agent.api.storage.CreateDatadiskTemplateCommand;
|
|||||||
import com.cloud.agent.api.storage.DownloadAnswer;
|
import com.cloud.agent.api.storage.DownloadAnswer;
|
||||||
import com.cloud.agent.api.storage.GetDatadisksAnswer;
|
import com.cloud.agent.api.storage.GetDatadisksAnswer;
|
||||||
import com.cloud.agent.api.storage.GetDatadisksCommand;
|
import com.cloud.agent.api.storage.GetDatadisksCommand;
|
||||||
import com.cloud.agent.api.storage.OVFPropertyTO;
|
|
||||||
import com.cloud.agent.api.to.DataObjectType;
|
import com.cloud.agent.api.to.DataObjectType;
|
||||||
import com.cloud.agent.api.to.DataTO;
|
import com.cloud.agent.api.to.DataTO;
|
||||||
import com.cloud.agent.api.to.DatadiskTO;
|
import com.cloud.agent.api.to.DatadiskTO;
|
||||||
import com.cloud.agent.api.to.NfsTO;
|
|
||||||
import com.cloud.alert.AlertManager;
|
import com.cloud.alert.AlertManager;
|
||||||
import com.cloud.configuration.Config;
|
import com.cloud.configuration.Config;
|
||||||
import com.cloud.exception.AgentUnavailableException;
|
import com.cloud.exception.AgentUnavailableException;
|
||||||
@ -72,14 +84,10 @@ import com.cloud.exception.OperationTimedoutException;
|
|||||||
import com.cloud.host.dao.HostDao;
|
import com.cloud.host.dao.HostDao;
|
||||||
import com.cloud.secstorage.CommandExecLogDao;
|
import com.cloud.secstorage.CommandExecLogDao;
|
||||||
import com.cloud.secstorage.CommandExecLogVO;
|
import com.cloud.secstorage.CommandExecLogVO;
|
||||||
import com.cloud.storage.DataStoreRole;
|
|
||||||
import com.cloud.storage.StorageManager;
|
import com.cloud.storage.StorageManager;
|
||||||
import com.cloud.storage.TemplateOVFPropertyVO;
|
|
||||||
import com.cloud.storage.Upload;
|
|
||||||
import com.cloud.storage.VMTemplateStorageResourceAssoc;
|
import com.cloud.storage.VMTemplateStorageResourceAssoc;
|
||||||
import com.cloud.storage.VMTemplateVO;
|
import com.cloud.storage.VMTemplateVO;
|
||||||
import com.cloud.storage.VolumeVO;
|
import com.cloud.storage.VolumeVO;
|
||||||
import com.cloud.storage.dao.TemplateOVFPropertiesDao;
|
|
||||||
import com.cloud.storage.dao.VMTemplateDao;
|
import com.cloud.storage.dao.VMTemplateDao;
|
||||||
import com.cloud.storage.dao.VMTemplateDetailsDao;
|
import com.cloud.storage.dao.VMTemplateDetailsDao;
|
||||||
import com.cloud.storage.dao.VMTemplateZoneDao;
|
import com.cloud.storage.dao.VMTemplateZoneDao;
|
||||||
@ -88,14 +96,14 @@ import com.cloud.storage.download.DownloadMonitor;
|
|||||||
import com.cloud.user.ResourceLimitService;
|
import com.cloud.user.ResourceLimitService;
|
||||||
import com.cloud.user.dao.AccountDao;
|
import com.cloud.user.dao.AccountDao;
|
||||||
import com.cloud.utils.NumbersUtil;
|
import com.cloud.utils.NumbersUtil;
|
||||||
import com.cloud.utils.crypt.DBEncryptionUtil;
|
|
||||||
import com.cloud.utils.db.TransactionLegacy;
|
import com.cloud.utils.db.TransactionLegacy;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import com.cloud.utils.net.Proxy;
|
import com.cloud.utils.net.Proxy;
|
||||||
import com.cloud.vm.dao.SecondaryStorageVmDao;
|
import com.cloud.vm.dao.SecondaryStorageVmDao;
|
||||||
|
|
||||||
public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
||||||
private static final Logger s_logger = Logger.getLogger(BaseImageStoreDriverImpl.class);
|
private static final Logger LOGGER = Logger.getLogger(BaseImageStoreDriverImpl.class);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected VMTemplateDao _templateDao;
|
protected VMTemplateDao _templateDao;
|
||||||
@Inject
|
@Inject
|
||||||
@ -115,7 +123,7 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
|||||||
@Inject
|
@Inject
|
||||||
AlertManager _alertMgr;
|
AlertManager _alertMgr;
|
||||||
@Inject
|
@Inject
|
||||||
VMTemplateDetailsDao _templateDetailsDao;
|
VMTemplateDetailsDao templateDetailsDao;
|
||||||
@Inject
|
@Inject
|
||||||
DefaultEndPointSelector _defaultEpSelector;
|
DefaultEndPointSelector _defaultEpSelector;
|
||||||
@Inject
|
@Inject
|
||||||
@ -123,8 +131,6 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
|||||||
@Inject
|
@Inject
|
||||||
ResourceLimitService _resourceLimitMgr;
|
ResourceLimitService _resourceLimitMgr;
|
||||||
@Inject
|
@Inject
|
||||||
TemplateOVFPropertiesDao templateOvfPropertiesDao;
|
|
||||||
@Inject
|
|
||||||
HostDao hostDao;
|
HostDao hostDao;
|
||||||
@Inject
|
@Inject
|
||||||
CommandExecLogDao _cmdExecLogDao;
|
CommandExecLogDao _cmdExecLogDao;
|
||||||
@ -137,6 +143,14 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
|||||||
|
|
||||||
protected String _proxy = null;
|
protected String _proxy = null;
|
||||||
|
|
||||||
|
private static Gson gson;
|
||||||
|
|
||||||
|
static {
|
||||||
|
GsonBuilder builder = new GsonBuilder();
|
||||||
|
builder.disableHtmlEscaping();
|
||||||
|
gson = builder.create();
|
||||||
|
}
|
||||||
|
|
||||||
protected Proxy getHttpProxy() {
|
protected Proxy getHttpProxy() {
|
||||||
if (_proxy == null) {
|
if (_proxy == null) {
|
||||||
return null;
|
return null;
|
||||||
@ -184,14 +198,14 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
|||||||
caller.setContext(context);
|
caller.setContext(context);
|
||||||
if (data.getType() == DataObjectType.TEMPLATE) {
|
if (data.getType() == DataObjectType.TEMPLATE) {
|
||||||
caller.setCallback(caller.getTarget().createTemplateAsyncCallback(null, null));
|
caller.setCallback(caller.getTarget().createTemplateAsyncCallback(null, null));
|
||||||
if (s_logger.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_logger.debug("Downloading template to data store " + dataStore.getId());
|
LOGGER.debug("Downloading template to data store " + dataStore.getId());
|
||||||
}
|
}
|
||||||
_downloadMonitor.downloadTemplateToStorage(data, caller);
|
_downloadMonitor.downloadTemplateToStorage(data, caller);
|
||||||
} else if (data.getType() == DataObjectType.VOLUME) {
|
} else if (data.getType() == DataObjectType.VOLUME) {
|
||||||
caller.setCallback(caller.getTarget().createVolumeAsyncCallback(null, null));
|
caller.setCallback(caller.getTarget().createVolumeAsyncCallback(null, null));
|
||||||
if (s_logger.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_logger.debug("Downloading volume to data store " + dataStore.getId());
|
LOGGER.debug("Downloading volume to data store " + dataStore.getId());
|
||||||
}
|
}
|
||||||
_downloadMonitor.downloadVolumeToStorage(data, caller);
|
_downloadMonitor.downloadVolumeToStorage(data, caller);
|
||||||
}
|
}
|
||||||
@ -201,43 +215,108 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
|||||||
* Persist OVF properties as template details for template with id = templateId
|
* Persist OVF properties as template details for template with id = templateId
|
||||||
*/
|
*/
|
||||||
private void persistOVFProperties(List<OVFPropertyTO> ovfProperties, long templateId) {
|
private void persistOVFProperties(List<OVFPropertyTO> ovfProperties, long templateId) {
|
||||||
List<TemplateOVFPropertyVO> listToPersist = new ArrayList<>();
|
if (LOGGER.isTraceEnabled()) {
|
||||||
|
LOGGER.trace(String.format("saving properties for template %d as details", templateId));
|
||||||
|
}
|
||||||
for (OVFPropertyTO property : ovfProperties) {
|
for (OVFPropertyTO property : ovfProperties) {
|
||||||
if (!templateOvfPropertiesDao.existsOption(templateId, property.getKey())) {
|
if (LOGGER.isTraceEnabled()) {
|
||||||
TemplateOVFPropertyVO option = new TemplateOVFPropertyVO(templateId, property.getKey(), property.getType(),
|
LOGGER.trace(String.format("saving property %s for template %d as detail", property.getKey(), templateId));
|
||||||
property.getValue(), property.getQualifiers(), property.isUserConfigurable(),
|
|
||||||
property.getLabel(), property.getDescription(), property.isPassword());
|
|
||||||
if (property.isPassword()) {
|
|
||||||
String encryptedPassword = DBEncryptionUtil.encrypt(property.getValue());
|
|
||||||
option.setValue(encryptedPassword);
|
|
||||||
}
|
}
|
||||||
listToPersist.add(option);
|
persistOvfPropertyAsSetOfTemplateDetails(templateId, property);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (CollectionUtils.isNotEmpty(listToPersist)) {
|
|
||||||
s_logger.debug("Persisting " + listToPersist.size() + " OVF properties for template " + templateId);
|
private void persistOvfPropertyAsSetOfTemplateDetails(long templateId, OVFPropertyTO property) {
|
||||||
templateOvfPropertiesDao.saveOptions(listToPersist);
|
String key = property.getKey();
|
||||||
|
String propKey = ImageStore.ACS_PROPERTY_PREFIX + key;
|
||||||
|
try {
|
||||||
|
String propValue = gson.toJson(property);
|
||||||
|
savePropertyAttribute(templateId, propKey, propValue);
|
||||||
|
} catch (RuntimeException re) {
|
||||||
|
LOGGER.error("gson marshalling of property object fails: " + propKey,re);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void persistNetworkRequirements(List<NetworkPrerequisiteTO> networkRequirements, long templateId) {
|
||||||
|
if (LOGGER.isTraceEnabled()) {
|
||||||
|
LOGGER.trace(String.format("saving network requirements for template %d as details", templateId));
|
||||||
|
}
|
||||||
|
for (NetworkPrerequisiteTO network : networkRequirements) {
|
||||||
|
if (LOGGER.isTraceEnabled()) {
|
||||||
|
LOGGER.trace(String.format("saving property %s for template %d as detail", network.getName(), templateId));
|
||||||
|
}
|
||||||
|
persistRequiredNetworkAsASingleTemplateDetail(templateId, network);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void persistDiskDefinitions(List<DatadiskTO> disks, long templateId) {
|
||||||
|
if (LOGGER.isTraceEnabled()) {
|
||||||
|
LOGGER.trace(String.format("saving disk definitionsn for template %d as details", templateId));
|
||||||
|
}
|
||||||
|
for (DatadiskTO disk : disks) {
|
||||||
|
if (LOGGER.isTraceEnabled()) {
|
||||||
|
LOGGER.trace(String.format("saving property %s for template %d as detail", disk.getDiskId(), templateId));
|
||||||
|
}
|
||||||
|
persistDiskDefinitionAsASingleTemplateDetail(templateId, disk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void persistRequiredNetworkAsASingleTemplateDetail(long templateId, NetworkPrerequisiteTO network) {
|
||||||
|
String key = network.getName();
|
||||||
|
String propKey = ImageStore.REQUIRED_NETWORK_PREFIX + key;
|
||||||
|
try {
|
||||||
|
String propValue = gson.toJson(network);
|
||||||
|
savePropertyAttribute(templateId, propKey, propValue);
|
||||||
|
} catch (RuntimeException re) {
|
||||||
|
LOGGER.warn("gson marshalling of network object fails: " + propKey,re);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void persistDiskDefinitionAsASingleTemplateDetail(long templateId, DatadiskTO disk) {
|
||||||
|
String key = disk.getDiskId();
|
||||||
|
String propKey = ImageStore.DISK_DEFINITION_PREFIX + key;
|
||||||
|
try {
|
||||||
|
String propValue = gson.toJson(disk);
|
||||||
|
savePropertyAttribute(templateId, propKey, propValue);
|
||||||
|
} catch (RuntimeException re) {
|
||||||
|
LOGGER.warn("gson marshalling of disk definition object fails: " + propKey,re);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void savePropertyAttribute(long templateId, String key, String value) {
|
||||||
|
if ( templateDetailsDao.findDetail(templateId,key) != null) {
|
||||||
|
LOGGER.debug(String.format("detail '%s' existed for template %d, deleting.", key, templateId));
|
||||||
|
templateDetailsDao.removeDetail(templateId,key);
|
||||||
|
}
|
||||||
|
if (LOGGER.isTraceEnabled()) {
|
||||||
|
LOGGER.trace(String.format("template detail for template %d to save is '%s': '%s'", templateId, key, value));
|
||||||
|
}
|
||||||
|
VMTemplateDetailVO detailVO = new VMTemplateDetailVO(templateId, key, value, false);
|
||||||
|
LOGGER.debug("Persisting template details " + detailVO.getName() + " from OVF properties for template " + templateId);
|
||||||
|
templateDetailsDao.persist(detailVO);
|
||||||
|
}
|
||||||
|
|
||||||
protected Void createTemplateAsyncCallback(AsyncCallbackDispatcher<? extends BaseImageStoreDriverImpl, DownloadAnswer> callback,
|
protected Void createTemplateAsyncCallback(AsyncCallbackDispatcher<? extends BaseImageStoreDriverImpl, DownloadAnswer> callback,
|
||||||
CreateContext<CreateCmdResult> context) {
|
CreateContext<CreateCmdResult> context) {
|
||||||
if (s_logger.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_logger.debug("Performing image store createTemplate async callback");
|
LOGGER.debug("Performing image store createTemplate async callback");
|
||||||
}
|
}
|
||||||
DownloadAnswer answer = callback.getResult();
|
DownloadAnswer answer = callback.getResult();
|
||||||
DataObject obj = context.data;
|
DataObject obj = context.data;
|
||||||
DataStore store = obj.getDataStore();
|
DataStore store = obj.getDataStore();
|
||||||
List<OVFPropertyTO> ovfProperties = answer.getOvfProperties();
|
List<OVFPropertyTO> ovfProperties = answer.getOvfProperties();
|
||||||
|
List<NetworkPrerequisiteTO> networkRequirements = answer.getNetworkRequirements();
|
||||||
|
List<DatadiskTO> disks = answer.getDisks();
|
||||||
|
OVFVirtualHardwareSectionTO ovfHardwareSection = answer.getOvfHardwareSection();
|
||||||
|
List<OVFEulaSectionTO> eulaSections = answer.getEulaSections();
|
||||||
|
|
||||||
|
VMTemplateVO template = _templateDao.findById(obj.getId());
|
||||||
TemplateDataStoreVO tmpltStoreVO = _templateStoreDao.findByStoreTemplate(store.getId(), obj.getId());
|
TemplateDataStoreVO tmpltStoreVO = _templateStoreDao.findByStoreTemplate(store.getId(), obj.getId());
|
||||||
if (tmpltStoreVO != null) {
|
if (tmpltStoreVO != null) {
|
||||||
if (tmpltStoreVO.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) {
|
if (tmpltStoreVO.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) {
|
||||||
if (CollectionUtils.isNotEmpty(ovfProperties)) {
|
persistExtraDetails(obj, ovfProperties, networkRequirements, disks, ovfHardwareSection, eulaSections);
|
||||||
persistOVFProperties(ovfProperties, obj.getId());
|
if (LOGGER.isDebugEnabled()) {
|
||||||
}
|
LOGGER.debug("Template is already in DOWNLOADED state, ignore further incoming DownloadAnswer");
|
||||||
if (s_logger.isDebugEnabled()) {
|
|
||||||
s_logger.debug("Template is already in DOWNLOADED state, ignore further incoming DownloadAnswer");
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -268,16 +347,14 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
|||||||
caller.complete(result);
|
caller.complete(result);
|
||||||
String msg = "Failed to register template: " + obj.getUuid() + " with error: " + answer.getErrorString();
|
String msg = "Failed to register template: " + obj.getUuid() + " with error: " + answer.getErrorString();
|
||||||
_alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_UPLOAD_FAILED, _vmTemplateZoneDao.listByTemplateId(obj.getId()).get(0).getZoneId(), null, msg, msg);
|
_alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_UPLOAD_FAILED, _vmTemplateZoneDao.listByTemplateId(obj.getId()).get(0).getZoneId(), null, msg, msg);
|
||||||
s_logger.error(msg);
|
LOGGER.error(msg);
|
||||||
} else if (answer.getDownloadStatus() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) {
|
} else if (answer.getDownloadStatus() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) {
|
||||||
if (answer.getCheckSum() != null) {
|
if (answer.getCheckSum() != null) {
|
||||||
VMTemplateVO templateDaoBuilder = _templateDao.createForUpdate();
|
VMTemplateVO templateDaoBuilder = _templateDao.createForUpdate();
|
||||||
templateDaoBuilder.setChecksum(answer.getCheckSum());
|
templateDaoBuilder.setChecksum(answer.getCheckSum());
|
||||||
_templateDao.update(obj.getId(), templateDaoBuilder);
|
_templateDao.update(obj.getId(), templateDaoBuilder);
|
||||||
}
|
}
|
||||||
if (CollectionUtils.isNotEmpty(ovfProperties)) {
|
persistExtraDetails(obj, ovfProperties, networkRequirements, disks, ovfHardwareSection, eulaSections);
|
||||||
persistOVFProperties(ovfProperties, obj.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
CreateCmdResult result = new CreateCmdResult(null, null);
|
CreateCmdResult result = new CreateCmdResult(null, null);
|
||||||
caller.complete(result);
|
caller.complete(result);
|
||||||
@ -285,6 +362,76 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void persistExtraDetails(DataObject obj, List<OVFPropertyTO> ovfProperties, List<NetworkPrerequisiteTO> networkRequirements, List<DatadiskTO> disks, OVFVirtualHardwareSectionTO ovfHardwareSection, List<OVFEulaSectionTO> eulaSections) {
|
||||||
|
if (LOGGER.isTraceEnabled()) {
|
||||||
|
LOGGER.trace(String.format("saving %d ovf properties for template '%s' as details", ovfProperties != null ? ovfProperties.size() : 0, obj.getUuid()));
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isNotEmpty(ovfProperties)) {
|
||||||
|
persistOVFProperties(ovfProperties, obj.getId());
|
||||||
|
}
|
||||||
|
if (LOGGER.isTraceEnabled()) {
|
||||||
|
LOGGER.trace(String.format("saving %d required network requirements for template '%s' as details", networkRequirements != null ? networkRequirements.size() : 0, obj.getUuid()));
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isNotEmpty(networkRequirements)) {
|
||||||
|
persistNetworkRequirements(networkRequirements, obj.getId());
|
||||||
|
}
|
||||||
|
if (LOGGER.isTraceEnabled()) {
|
||||||
|
LOGGER.trace(String.format("saving %d disks definitions for template '%s' as details", disks != null ? disks.size() : 0, obj.getUuid()));
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isNotEmpty(disks)) {
|
||||||
|
persistDiskDefinitions(disks, obj.getId());
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isNotEmpty(eulaSections)) {
|
||||||
|
persistEulaSectionsAsTemplateDetails(eulaSections, obj.getId());
|
||||||
|
}
|
||||||
|
persistOVFHardwareSectionAsTemplateDetails(ovfHardwareSection, obj.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void persistEulaSectionsAsTemplateDetails(List<OVFEulaSectionTO> eulaSections, long templateId) {
|
||||||
|
CompressionUtil compressionUtil = new CompressionUtil();
|
||||||
|
for (OVFEulaSectionTO eulaSectionTO : eulaSections) {
|
||||||
|
String key = ImageStore.OVF_EULA_SECTION_PREFIX + eulaSectionTO.getIndex() + "-" + eulaSectionTO.getInfo();
|
||||||
|
byte[] compressedLicense = eulaSectionTO.getCompressedLicense();
|
||||||
|
try {
|
||||||
|
String detailValue = compressionUtil.decompressByteArary(compressedLicense);
|
||||||
|
savePropertyAttribute(templateId, key, detailValue);
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOGGER.error("Could not decompress the license for template " + templateId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persist template details for template with ID=templateId, with name=key and value=json(object)
|
||||||
|
*/
|
||||||
|
private void persistTemplateDetailGsonEncoded(long templateId, String key, Object object) {
|
||||||
|
try {
|
||||||
|
String propValue = gson.toJson(object);
|
||||||
|
savePropertyAttribute(templateId, key, propValue);
|
||||||
|
} catch (RuntimeException re) {
|
||||||
|
LOGGER.error("gson marshalling of property object fails: " + key, re);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void persistOVFHardwareSectionAsTemplateDetails(OVFVirtualHardwareSectionTO ovfHardwareSection, long templateId) {
|
||||||
|
if (ovfHardwareSection != null) {
|
||||||
|
if (CollectionUtils.isNotEmpty(ovfHardwareSection.getConfigurations())) {
|
||||||
|
for (OVFConfigurationTO configuration : ovfHardwareSection.getConfigurations()) {
|
||||||
|
String key = configuration.getId();
|
||||||
|
String propKey = ImageStore.OVF_HARDWARE_CONFIGURATION_PREFIX + configuration.getIndex() + "-" + key;
|
||||||
|
persistTemplateDetailGsonEncoded(templateId, propKey, configuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isNotEmpty(ovfHardwareSection.getCommonHardwareItems())) {
|
||||||
|
for (OVFVirtualHardwareItemTO item : ovfHardwareSection.getCommonHardwareItems()) {
|
||||||
|
String key = item.getResourceType().getName().trim().replaceAll("\\s","") + "-" + item.getInstanceId();
|
||||||
|
String propKey = ImageStore.OVF_HARDWARE_ITEM_PREFIX + key;
|
||||||
|
persistTemplateDetailGsonEncoded(templateId, propKey, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected Void
|
protected Void
|
||||||
createVolumeAsyncCallback(AsyncCallbackDispatcher<? extends BaseImageStoreDriverImpl, DownloadAnswer> callback, CreateContext<CreateCmdResult> context) {
|
createVolumeAsyncCallback(AsyncCallbackDispatcher<? extends BaseImageStoreDriverImpl, DownloadAnswer> callback, CreateContext<CreateCmdResult> context) {
|
||||||
DownloadAnswer answer = callback.getResult();
|
DownloadAnswer answer = callback.getResult();
|
||||||
@ -294,8 +441,8 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
|||||||
VolumeDataStoreVO volStoreVO = _volumeStoreDao.findByStoreVolume(store.getId(), obj.getId());
|
VolumeDataStoreVO volStoreVO = _volumeStoreDao.findByStoreVolume(store.getId(), obj.getId());
|
||||||
if (volStoreVO != null) {
|
if (volStoreVO != null) {
|
||||||
if (volStoreVO.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) {
|
if (volStoreVO.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) {
|
||||||
if (s_logger.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_logger.debug("Volume is already in DOWNLOADED state, ignore further incoming DownloadAnswer");
|
LOGGER.debug("Volume is already in DOWNLOADED state, ignore further incoming DownloadAnswer");
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -327,7 +474,7 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
|||||||
String msg = "Failed to upload volume: " + obj.getUuid() + " with error: " + answer.getErrorString();
|
String msg = "Failed to upload volume: " + obj.getUuid() + " with error: " + answer.getErrorString();
|
||||||
_alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_UPLOAD_FAILED,
|
_alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_UPLOAD_FAILED,
|
||||||
(volStoreVO == null ? -1L : volStoreVO.getZoneId()), null, msg, msg);
|
(volStoreVO == null ? -1L : volStoreVO.getZoneId()), null, msg, msg);
|
||||||
s_logger.error(msg);
|
LOGGER.error(msg);
|
||||||
} else if (answer.getDownloadStatus() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) {
|
} else if (answer.getDownloadStatus() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) {
|
||||||
CreateCmdResult result = new CreateCmdResult(null, null);
|
CreateCmdResult result = new CreateCmdResult(null, null);
|
||||||
caller.complete(result);
|
caller.complete(result);
|
||||||
@ -344,7 +491,7 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
|||||||
Answer answer = null;
|
Answer answer = null;
|
||||||
if (ep == null) {
|
if (ep == null) {
|
||||||
String errMsg = "No remote endpoint to send command, check if host or ssvm is down?";
|
String errMsg = "No remote endpoint to send command, check if host or ssvm is down?";
|
||||||
s_logger.error(errMsg);
|
LOGGER.error(errMsg);
|
||||||
answer = new Answer(cmd, false, errMsg);
|
answer = new Answer(cmd, false, errMsg);
|
||||||
} else {
|
} else {
|
||||||
answer = ep.sendMessage(cmd);
|
answer = ep.sendMessage(cmd);
|
||||||
@ -353,7 +500,7 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
|||||||
result.setResult(answer.getDetails());
|
result.setResult(answer.getDetails());
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
s_logger.debug("Unable to destoy " + data.getType().toString() + ": " + data.getId(), ex);
|
LOGGER.debug("Unable to destoy " + data.getType().toString() + ": " + data.getId(), ex);
|
||||||
result.setResult(ex.toString());
|
result.setResult(ex.toString());
|
||||||
}
|
}
|
||||||
callback.complete(result);
|
callback.complete(result);
|
||||||
@ -377,7 +524,7 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
|||||||
List<EndPoint> eps = _epSelector.findAllEndpointsForScope(srcdata.getDataStore());
|
List<EndPoint> eps = _epSelector.findAllEndpointsForScope(srcdata.getDataStore());
|
||||||
if (eps == null || eps.isEmpty()) {
|
if (eps == null || eps.isEmpty()) {
|
||||||
String errMsg = "No remote endpoint to send command, check if host or ssvm is down?";
|
String errMsg = "No remote endpoint to send command, check if host or ssvm is down?";
|
||||||
s_logger.error(errMsg);
|
LOGGER.error(errMsg);
|
||||||
answer = new Answer(cmd, false, errMsg);
|
answer = new Answer(cmd, false, errMsg);
|
||||||
} else {
|
} else {
|
||||||
// select endpoint with least number of commands running on them
|
// select endpoint with least number of commands running on them
|
||||||
@ -414,25 +561,16 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
|||||||
return answer;
|
return answer;
|
||||||
} catch (AgentUnavailableException e) {
|
} catch (AgentUnavailableException e) {
|
||||||
errMsg = e.toString();
|
errMsg = e.toString();
|
||||||
s_logger.debug("Failed to send command, due to Agent:" + endPoint.getId() + ", " + e.toString());
|
LOGGER.debug("Failed to send command, due to Agent:" + endPoint.getId() + ", " + e.toString());
|
||||||
} catch (OperationTimedoutException e) {
|
} catch (OperationTimedoutException e) {
|
||||||
errMsg = e.toString();
|
errMsg = e.toString();
|
||||||
s_logger.debug("Failed to send command, due to Agent:" + endPoint.getId() + ", " + e.toString());
|
LOGGER.debug("Failed to send command, due to Agent:" + endPoint.getId() + ", " + e.toString());
|
||||||
}
|
}
|
||||||
throw new CloudRuntimeException("Failed to send command, due to Agent:" + endPoint.getId() + ", " + errMsg);
|
throw new CloudRuntimeException("Failed to send command, due to Agent:" + endPoint.getId() + ", " + errMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canCopy(DataObject srcData, DataObject destData) {
|
public boolean canCopy(DataObject srcData, DataObject destData) {
|
||||||
DataStore srcStore = srcData.getDataStore();
|
|
||||||
DataStore destStore = destData.getDataStore();
|
|
||||||
if ((srcData.getDataStore().getTO() instanceof NfsTO && destData.getDataStore().getTO() instanceof NfsTO) &&
|
|
||||||
(srcStore.getRole() == DataStoreRole.Image && destStore.getRole() == DataStoreRole.Image) &&
|
|
||||||
((srcData.getType() == DataObjectType.TEMPLATE && destData.getType() == DataObjectType.TEMPLATE) ||
|
|
||||||
(srcData.getType() == DataObjectType.SNAPSHOT && destData.getType() == DataObjectType.SNAPSHOT) ||
|
|
||||||
(srcData.getType() == DataObjectType.VOLUME && destData.getType() == DataObjectType.VOLUME))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,18 +583,18 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<DatadiskTO> getDataDiskTemplates(DataObject obj) {
|
public List<DatadiskTO> getDataDiskTemplates(DataObject obj, String configurationId) {
|
||||||
List<DatadiskTO> dataDiskDetails = new ArrayList<DatadiskTO>();
|
List<DatadiskTO> dataDiskDetails = new ArrayList<DatadiskTO>();
|
||||||
if (s_logger.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_logger.debug("Get the data disks present in the OVA template");
|
LOGGER.debug("Get the data disks present in the OVA template");
|
||||||
}
|
}
|
||||||
DataStore store = obj.getDataStore();
|
DataStore store = obj.getDataStore();
|
||||||
GetDatadisksCommand cmd = new GetDatadisksCommand(obj.getTO());
|
GetDatadisksCommand cmd = new GetDatadisksCommand(obj.getTO(), configurationId);
|
||||||
EndPoint ep = _defaultEpSelector.select(store);
|
EndPoint ep = _defaultEpSelector.select(store);
|
||||||
Answer answer = null;
|
Answer answer = null;
|
||||||
if (ep == null) {
|
if (ep == null) {
|
||||||
String errMsg = "No remote endpoint to send command, check if host or ssvm is down?";
|
String errMsg = "No remote endpoint to send command, check if host or ssvm is down?";
|
||||||
s_logger.error(errMsg);
|
LOGGER.error(errMsg);
|
||||||
answer = new Answer(cmd, false, errMsg);
|
answer = new Answer(cmd, false, errMsg);
|
||||||
} else {
|
} else {
|
||||||
answer = ep.sendMessage(cmd);
|
answer = ep.sendMessage(cmd);
|
||||||
@ -475,14 +613,14 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
|||||||
public Void createDataDiskTemplateAsync(TemplateInfo dataDiskTemplate, String path, String diskId, boolean bootable, long fileSize, AsyncCompletionCallback<CreateCmdResult> callback) {
|
public Void createDataDiskTemplateAsync(TemplateInfo dataDiskTemplate, String path, String diskId, boolean bootable, long fileSize, AsyncCompletionCallback<CreateCmdResult> callback) {
|
||||||
Answer answer = null;
|
Answer answer = null;
|
||||||
String errMsg = null;
|
String errMsg = null;
|
||||||
if (s_logger.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
s_logger.debug("Create Datadisk template: " + dataDiskTemplate.getId());
|
LOGGER.debug("Create Datadisk template: " + dataDiskTemplate.getId());
|
||||||
}
|
}
|
||||||
CreateDatadiskTemplateCommand cmd = new CreateDatadiskTemplateCommand(dataDiskTemplate.getTO(), path, diskId, fileSize, bootable);
|
CreateDatadiskTemplateCommand cmd = new CreateDatadiskTemplateCommand(dataDiskTemplate.getTO(), path, diskId, fileSize, bootable);
|
||||||
EndPoint ep = _defaultEpSelector.select(dataDiskTemplate.getDataStore());
|
EndPoint ep = _defaultEpSelector.select(dataDiskTemplate.getDataStore());
|
||||||
if (ep == null) {
|
if (ep == null) {
|
||||||
errMsg = "No remote endpoint to send command, check if host or ssvm is down?";
|
errMsg = "No remote endpoint to send command, check if host or ssvm is down?";
|
||||||
s_logger.error(errMsg);
|
LOGGER.error(errMsg);
|
||||||
answer = new Answer(cmd, false, errMsg);
|
answer = new Answer(cmd, false, errMsg);
|
||||||
} else {
|
} else {
|
||||||
answer = ep.sendMessage(cmd);
|
answer = ep.sendMessage(cmd);
|
||||||
@ -496,8 +634,12 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Integer getCopyCmdsCountToSpecificSSVM(Long ssvmId) {
|
||||||
|
return _cmdExecLogDao.getCopyCmdCountForSSVM(ssvmId);
|
||||||
|
}
|
||||||
|
|
||||||
private List<Long> ssvmWithLeastMigrateJobs() {
|
private List<Long> ssvmWithLeastMigrateJobs() {
|
||||||
s_logger.debug("Picking ssvm from the pool with least commands running on it");
|
LOGGER.debug("Picking ssvm from the pool with least commands running on it");
|
||||||
String query = "select host_id, count(*) from cmd_exec_log group by host_id order by 2;";
|
String query = "select host_id, count(*) from cmd_exec_log group by host_id order by 2;";
|
||||||
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
||||||
|
|
||||||
@ -510,7 +652,7 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver {
|
|||||||
result.add((long) rs.getInt(1));
|
result.add((long) rs.getInt(1));
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
s_logger.debug("SQLException caught", e);
|
LOGGER.debug("SQLException caught", e);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,7 +37,7 @@ public interface ImageStoreDriver extends DataStoreDriver {
|
|||||||
|
|
||||||
void deleteEntityExtractUrl(DataStore store, String installPath, String url, Upload.Type entityType);
|
void deleteEntityExtractUrl(DataStore store, String installPath, String url, Upload.Type entityType);
|
||||||
|
|
||||||
List<DatadiskTO> getDataDiskTemplates(DataObject obj);
|
List<DatadiskTO> getDataDiskTemplates(DataObject obj, String configurationId);
|
||||||
|
|
||||||
Void createDataDiskTemplateAsync(TemplateInfo dataDiskTemplate, String path, String diskId, boolean bootable, long fileSize, AsyncCompletionCallback<CreateCmdResult> callback);
|
Void createDataDiskTemplateAsync(TemplateInfo dataDiskTemplate, String path, String diskId, boolean bootable, long fileSize, AsyncCompletionCallback<CreateCmdResult> callback);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,314 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 org.apache.cloudstack.storage.image;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.apache.cloudstack.engine.cloud.entity.api.TemplateEntity;
|
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
|
|
||||||
import org.apache.cloudstack.storage.image.datastore.ImageStoreInfo;
|
|
||||||
|
|
||||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
|
||||||
import com.cloud.storage.Storage.ImageFormat;
|
|
||||||
import com.cloud.storage.Storage.TemplateType;
|
|
||||||
import com.cloud.template.VirtualMachineTemplate;
|
|
||||||
|
|
||||||
public class TemplateEntityImpl implements TemplateEntity {
|
|
||||||
protected TemplateInfo templateInfo;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public State getState() {
|
|
||||||
return templateInfo.getState();
|
|
||||||
}
|
|
||||||
|
|
||||||
public TemplateEntityImpl(TemplateInfo templateInfo) {
|
|
||||||
this.templateInfo = templateInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImageStoreInfo getImageDataStore() {
|
|
||||||
return (ImageStoreInfo)templateInfo.getDataStore();
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getImageDataStoreId() {
|
|
||||||
return getImageDataStore().getImageStoreId();
|
|
||||||
}
|
|
||||||
|
|
||||||
public TemplateInfo getTemplateInfo() {
|
|
||||||
return templateInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUuid() {
|
|
||||||
return templateInfo.getUuid();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getId() {
|
|
||||||
return templateInfo.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getExternalId() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getCurrentState() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDesiredState() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Date getCreatedTime() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Date getLastUpdatedTime() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getOwner() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, String> getDetails() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isDynamicallyScalable() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addDetail(String name, String value) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delDetail(String name, String value) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateDetail(String name, String value) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Method> getApplicableActions() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isFeatured() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isPublicTemplate() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isExtractable() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ImageFormat getFormat() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRequiresHvm() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDisplayText() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEnablePassword() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEnableSshKey() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCrossZones() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Date getCreated() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getGuestOSId() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isBootable() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TemplateType getTemplateType() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HypervisorType getHypervisorType() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBits() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUniqueName() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUrl() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getChecksum() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Long getSourceTemplateId() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getTemplateTag() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getAccountId() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getDomainId() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getPhysicalSize() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getVirtualSize() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?> getEntityType() {
|
|
||||||
return VirtualMachineTemplate.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getUpdatedCount() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void incrUpdatedCount() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Date getUpdated() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Long getParentTemplateId() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -218,12 +218,12 @@ public class PrimaryDataStoreImpl implements PrimaryDataStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TemplateInfo getTemplate(long templateId) {
|
public TemplateInfo getTemplate(long templateId, String configuration) {
|
||||||
VMTemplateStoragePoolVO template = templatePoolDao.findByPoolTemplate(getId(), templateId);
|
VMTemplateStoragePoolVO template = templatePoolDao.findByPoolTemplate(getId(), templateId, configuration);
|
||||||
if (template == null || template.getState() != ObjectInDataStoreStateMachine.State.Ready) {
|
if (template == null || template.getState() != ObjectInDataStoreStateMachine.State.Ready) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return imageDataFactory.getTemplate(templateId, this);
|
return imageDataFactory.getTemplateOnPrimaryStorage(templateId, this, configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -264,18 +264,26 @@ public class PrimaryDataStoreImpl implements PrimaryDataStore {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public DataObject create(DataObject dataObject) {
|
public DataObject create(DataObject dataObject) {
|
||||||
return create(dataObject, true);
|
return create(dataObject, true, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataObject create(DataObject dataObject, String configuration) {
|
||||||
|
return create(dataObject, true, configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Please read the comment for the create(DataObject) method if you are planning on passing in "false" for createEntryInTempSpoolRef.
|
* Please read the comment for the create(DataObject) method if you are planning on passing in "false" for createEntryInTempSpoolRef.
|
||||||
|
*
|
||||||
|
* The parameter configuration allows storing multiple configurations of the
|
||||||
|
* base template appliance in primary storage (VMware supported) - null by default or no configurations
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public DataObject create(DataObject obj, boolean createEntryInTempSpoolRef) {
|
public DataObject create(DataObject obj, boolean createEntryInTempSpoolRef, String configuration) {
|
||||||
// create template on primary storage
|
// create template on primary storage
|
||||||
if (obj.getType() == DataObjectType.TEMPLATE && (!isManaged() || (createEntryInTempSpoolRef && canCloneVolume()))) {
|
if (obj.getType() == DataObjectType.TEMPLATE && (!isManaged() || (createEntryInTempSpoolRef && canCloneVolume()))) {
|
||||||
try {
|
try {
|
||||||
String templateIdPoolIdString = "templateId:" + obj.getId() + "poolId:" + getId();
|
String templateIdPoolIdString = "templateId:" + obj.getId() + "poolId:" + getId() + "conf:" + configuration;
|
||||||
VMTemplateStoragePoolVO templateStoragePoolRef;
|
VMTemplateStoragePoolVO templateStoragePoolRef;
|
||||||
GlobalLock lock = GlobalLock.getInternLock(templateIdPoolIdString);
|
GlobalLock lock = GlobalLock.getInternLock(templateIdPoolIdString);
|
||||||
if (!lock.lock(5)) {
|
if (!lock.lock(5)) {
|
||||||
@ -283,20 +291,20 @@ public class PrimaryDataStoreImpl implements PrimaryDataStore {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
templateStoragePoolRef = templatePoolDao.findByPoolTemplate(getId(), obj.getId());
|
templateStoragePoolRef = templatePoolDao.findByPoolTemplate(getId(), obj.getId(), configuration);
|
||||||
if (templateStoragePoolRef == null) {
|
if (templateStoragePoolRef == null) {
|
||||||
|
|
||||||
if (s_logger.isDebugEnabled()) {
|
if (s_logger.isDebugEnabled()) {
|
||||||
s_logger.debug("Not found (" + templateIdPoolIdString + ") in template_spool_ref, persisting it");
|
s_logger.debug("Not found (" + templateIdPoolIdString + ") in template_spool_ref, persisting it");
|
||||||
}
|
}
|
||||||
templateStoragePoolRef = new VMTemplateStoragePoolVO(getId(), obj.getId());
|
templateStoragePoolRef = new VMTemplateStoragePoolVO(getId(), obj.getId(), configuration);
|
||||||
templateStoragePoolRef = templatePoolDao.persist(templateStoragePoolRef);
|
templateStoragePoolRef = templatePoolDao.persist(templateStoragePoolRef);
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
if (s_logger.isDebugEnabled()) {
|
if (s_logger.isDebugEnabled()) {
|
||||||
s_logger.debug("Failed to insert (" + templateIdPoolIdString + ") to template_spool_ref", t);
|
s_logger.debug("Failed to insert (" + templateIdPoolIdString + ") to template_spool_ref", t);
|
||||||
}
|
}
|
||||||
templateStoragePoolRef = templatePoolDao.findByPoolTemplate(getId(), obj.getId());
|
templateStoragePoolRef = templatePoolDao.findByPoolTemplate(getId(), obj.getId(), configuration);
|
||||||
if (templateStoragePoolRef == null) {
|
if (templateStoragePoolRef == null) {
|
||||||
throw new CloudRuntimeException("Failed to create template storage pool entry");
|
throw new CloudRuntimeException("Failed to create template storage pool entry");
|
||||||
} else {
|
} else {
|
||||||
@ -321,7 +329,7 @@ public class PrimaryDataStoreImpl implements PrimaryDataStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return objectInStoreMgr.get(obj, this);
|
return objectInStoreMgr.get(obj, this, configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -20,6 +20,14 @@ import java.util.Date;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import com.cloud.storage.MigrationOptions;
|
||||||
|
import com.cloud.storage.VMTemplateVO;
|
||||||
|
import com.cloud.storage.VolumeDetailVO;
|
||||||
|
import com.cloud.storage.dao.VMTemplateDao;
|
||||||
|
import com.cloud.storage.dao.VolumeDetailsDao;
|
||||||
|
import com.cloud.vm.VmDetailConstants;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
|
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
|
||||||
@ -30,7 +38,6 @@ import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
|
|||||||
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO;
|
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO;
|
||||||
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
import com.cloud.agent.api.Answer;
|
import com.cloud.agent.api.Answer;
|
||||||
import com.cloud.agent.api.storage.DownloadAnswer;
|
import com.cloud.agent.api.storage.DownloadAnswer;
|
||||||
@ -71,6 +78,10 @@ public class VolumeObject implements VolumeInfo {
|
|||||||
VMInstanceDao vmInstanceDao;
|
VMInstanceDao vmInstanceDao;
|
||||||
@Inject
|
@Inject
|
||||||
DiskOfferingDao diskOfferingDao;
|
DiskOfferingDao diskOfferingDao;
|
||||||
|
@Inject
|
||||||
|
VMTemplateDao templateDao;
|
||||||
|
@Inject
|
||||||
|
VolumeDetailsDao volumeDetailsDao;
|
||||||
private Object payload;
|
private Object payload;
|
||||||
private MigrationOptions migrationOptions;
|
private MigrationOptions migrationOptions;
|
||||||
private boolean directDownload;
|
private boolean directDownload;
|
||||||
@ -357,7 +368,7 @@ public class VolumeObject implements VolumeInfo {
|
|||||||
if (dataStore == null) {
|
if (dataStore == null) {
|
||||||
throw new CloudRuntimeException("datastore must be set before using this object");
|
throw new CloudRuntimeException("datastore must be set before using this object");
|
||||||
}
|
}
|
||||||
DataObjectInStore obj = objectInStoreMgr.findObject(volumeVO.getId(), DataObjectType.VOLUME, dataStore.getId(), dataStore.getRole());
|
DataObjectInStore obj = objectInStoreMgr.findObject(volumeVO.getId(), DataObjectType.VOLUME, dataStore.getId(), dataStore.getRole(), null);
|
||||||
if (obj.getState() != ObjectInDataStoreStateMachine.State.Ready) {
|
if (obj.getState() != ObjectInDataStoreStateMachine.State.Ready) {
|
||||||
return dataStore.getUri() + "&" + EncodingType.OBJTYPE + "=" + DataObjectType.VOLUME + "&" + EncodingType.SIZE + "=" + volumeVO.getSize() + "&" +
|
return dataStore.getUri() + "&" + EncodingType.OBJTYPE + "=" + DataObjectType.VOLUME + "&" + EncodingType.SIZE + "=" + volumeVO.getSize() + "&" +
|
||||||
EncodingType.NAME + "=" + volumeVO.getName();
|
EncodingType.NAME + "=" + volumeVO.getName();
|
||||||
@ -391,9 +402,7 @@ public class VolumeObject implements VolumeInfo {
|
|||||||
if (event == ObjectInDataStoreStateMachine.Event.CreateOnlyRequested) {
|
if (event == ObjectInDataStoreStateMachine.Event.CreateOnlyRequested) {
|
||||||
volEvent = Volume.Event.UploadRequested;
|
volEvent = Volume.Event.UploadRequested;
|
||||||
} else if (event == ObjectInDataStoreStateMachine.Event.MigrationRequested) {
|
} else if (event == ObjectInDataStoreStateMachine.Event.MigrationRequested) {
|
||||||
volEvent = Event.CopyRequested;
|
volEvent = Volume.Event.CopyRequested;
|
||||||
} else if (event == ObjectInDataStoreStateMachine.Event.MigrateDataRequested) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (event == ObjectInDataStoreStateMachine.Event.CreateRequested || event == ObjectInDataStoreStateMachine.Event.CreateOnlyRequested) {
|
if (event == ObjectInDataStoreStateMachine.Event.CreateRequested || event == ObjectInDataStoreStateMachine.Event.CreateOnlyRequested) {
|
||||||
@ -436,6 +445,18 @@ public class VolumeObject implements VolumeInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDeployAsIs() {
|
||||||
|
VMTemplateVO template = templateDao.findById(getTemplateId());
|
||||||
|
return template != null && template.isDeployAsIs();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDeployAsIsConfiguration() {
|
||||||
|
VolumeDetailVO detail = volumeDetailsDao.findDetail(getId(), VmDetailConstants.DEPLOY_AS_IS_CONFIGURATION);
|
||||||
|
return detail != null ? detail.getValue() : null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void processEventOnly(ObjectInDataStoreStateMachine.Event event) {
|
public void processEventOnly(ObjectInDataStoreStateMachine.Event event) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -121,6 +121,8 @@ import com.cloud.utils.db.GlobalLock;
|
|||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import com.cloud.vm.VirtualMachine;
|
import com.cloud.vm.VirtualMachine;
|
||||||
|
|
||||||
|
import static com.cloud.storage.resource.StorageProcessor.REQUEST_TEMPLATE_RELOAD;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class VolumeServiceImpl implements VolumeService {
|
public class VolumeServiceImpl implements VolumeService {
|
||||||
private static final Logger s_logger = Logger.getLogger(VolumeServiceImpl.class);
|
private static final Logger s_logger = Logger.getLogger(VolumeServiceImpl.class);
|
||||||
@ -530,7 +532,7 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
int sleepTime = 120;
|
int sleepTime = 120;
|
||||||
int tries = storagePoolMaxWaitSeconds / sleepTime;
|
int tries = storagePoolMaxWaitSeconds / sleepTime;
|
||||||
while (tries > 0) {
|
while (tries > 0) {
|
||||||
TemplateInfo tmpl = store.getTemplate(template.getId());
|
TemplateInfo tmpl = store.getTemplate(template.getId(), null);
|
||||||
if (tmpl != null) {
|
if (tmpl != null) {
|
||||||
return tmpl;
|
return tmpl;
|
||||||
}
|
}
|
||||||
@ -546,9 +548,10 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
|
|
||||||
@DB
|
@DB
|
||||||
protected void createBaseImageAsync(VolumeInfo volume, PrimaryDataStore dataStore, TemplateInfo template, AsyncCallFuture<VolumeApiResult> future) {
|
protected void createBaseImageAsync(VolumeInfo volume, PrimaryDataStore dataStore, TemplateInfo template, AsyncCallFuture<VolumeApiResult> future) {
|
||||||
DataObject templateOnPrimaryStoreObj = dataStore.create(template);
|
String deployAsIsConfiguration = volume.getDeployAsIsConfiguration();
|
||||||
|
DataObject templateOnPrimaryStoreObj = dataStore.create(template, deployAsIsConfiguration);
|
||||||
|
|
||||||
VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(dataStore.getId(), template.getId());
|
VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(dataStore.getId(), template.getId(), deployAsIsConfiguration);
|
||||||
if (templatePoolRef == null) {
|
if (templatePoolRef == null) {
|
||||||
throw new CloudRuntimeException("Failed to find template " + template.getUniqueName() + " in storage pool " + dataStore.getId());
|
throw new CloudRuntimeException("Failed to find template " + template.getUniqueName() + " in storage pool " + dataStore.getId());
|
||||||
} else {
|
} else {
|
||||||
@ -571,8 +574,8 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
if (s_logger.isDebugEnabled()) {
|
if (s_logger.isDebugEnabled()) {
|
||||||
s_logger.info("Unable to acquire lock on VMTemplateStoragePool " + templatePoolRefId);
|
s_logger.info("Unable to acquire lock on VMTemplateStoragePool " + templatePoolRefId);
|
||||||
}
|
}
|
||||||
templatePoolRef = _tmpltPoolDao.findByPoolTemplate(dataStore.getId(), template.getId());
|
templatePoolRef = _tmpltPoolDao.findByPoolTemplate(dataStore.getId(), template.getId(), deployAsIsConfiguration);
|
||||||
if (templatePoolRef != null && templatePoolRef.getState() == ObjectInDataStoreStateMachine.State.Ready) {
|
if (templatePoolRef != null && templatePoolRef.getState() == ObjectInDataStoreStateMachine.State.Ready && !template.isDeployAsIs()) {
|
||||||
s_logger.info(
|
s_logger.info(
|
||||||
"Unable to acquire lock on VMTemplateStoragePool " + templatePoolRefId + ", But Template " + template.getUniqueName() + " is already copied to primary storage, skip copying");
|
"Unable to acquire lock on VMTemplateStoragePool " + templatePoolRefId + ", But Template " + template.getUniqueName() + " is already copied to primary storage, skip copying");
|
||||||
createVolumeFromBaseImageAsync(volume, templateOnPrimaryStoreObj, dataStore, future);
|
createVolumeFromBaseImageAsync(volume, templateOnPrimaryStoreObj, dataStore, future);
|
||||||
@ -585,7 +588,7 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
s_logger.info("lock is acquired for VMTemplateStoragePool " + templatePoolRefId);
|
s_logger.info("lock is acquired for VMTemplateStoragePool " + templatePoolRefId);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (templatePoolRef.getState() == ObjectInDataStoreStateMachine.State.Ready) {
|
if (templatePoolRef.getState() == ObjectInDataStoreStateMachine.State.Ready && !template.isDeployAsIs()) {
|
||||||
s_logger.info("Template " + template.getUniqueName() + " is already copied to primary storage, skip copying");
|
s_logger.info("Template " + template.getUniqueName() + " is already copied to primary storage, skip copying");
|
||||||
createVolumeFromBaseImageAsync(volume, templateOnPrimaryStoreObj, dataStore, future);
|
createVolumeFromBaseImageAsync(volume, templateOnPrimaryStoreObj, dataStore, future);
|
||||||
return;
|
return;
|
||||||
@ -595,7 +598,7 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
s_logger.debug("failed to create template on storage", e);
|
s_logger.debug("failed to create template on storage", e);
|
||||||
templateOnPrimaryStoreObj.processEvent(Event.OperationFailed);
|
templateOnPrimaryStoreObj.processEvent(Event.OperationFailed);
|
||||||
dataStore.create(template); // make sure that template_spool_ref entry is still present so that the second thread can acquire the lock
|
dataStore.create(template, deployAsIsConfiguration); // make sure that template_spool_ref entry is still present so that the second thread can acquire the lock
|
||||||
VolumeApiResult result = new VolumeApiResult(volume);
|
VolumeApiResult result = new VolumeApiResult(volume);
|
||||||
result.setResult(e.toString());
|
result.setResult(e.toString());
|
||||||
future.complete(result);
|
future.complete(result);
|
||||||
@ -705,14 +708,16 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
private final AsyncCallFuture<VolumeApiResult> future;
|
private final AsyncCallFuture<VolumeApiResult> future;
|
||||||
private final DataObject templateOnStore;
|
private final DataObject templateOnStore;
|
||||||
private final SnapshotInfo snapshot;
|
private final SnapshotInfo snapshot;
|
||||||
|
private final String deployAsIsConfiguration;
|
||||||
|
|
||||||
public CreateVolumeFromBaseImageContext(AsyncCompletionCallback<T> callback, DataObject vo, DataStore primaryStore, DataObject templateOnStore, AsyncCallFuture<VolumeApiResult> future,
|
public CreateVolumeFromBaseImageContext(AsyncCompletionCallback<T> callback, DataObject vo, DataStore primaryStore, DataObject templateOnStore, AsyncCallFuture<VolumeApiResult> future,
|
||||||
SnapshotInfo snapshot) {
|
SnapshotInfo snapshot, String configuration) {
|
||||||
super(callback);
|
super(callback);
|
||||||
this.vo = vo;
|
this.vo = vo;
|
||||||
this.future = future;
|
this.future = future;
|
||||||
this.templateOnStore = templateOnStore;
|
this.templateOnStore = templateOnStore;
|
||||||
this.snapshot = snapshot;
|
this.snapshot = snapshot;
|
||||||
|
this.deployAsIsConfiguration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncCallFuture<VolumeApiResult> getFuture() {
|
public AsyncCallFuture<VolumeApiResult> getFuture() {
|
||||||
@ -722,15 +727,16 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
|
|
||||||
@DB
|
@DB
|
||||||
protected void createVolumeFromBaseImageAsync(VolumeInfo volume, DataObject templateOnPrimaryStore, PrimaryDataStore pd, AsyncCallFuture<VolumeApiResult> future) {
|
protected void createVolumeFromBaseImageAsync(VolumeInfo volume, DataObject templateOnPrimaryStore, PrimaryDataStore pd, AsyncCallFuture<VolumeApiResult> future) {
|
||||||
DataObject volumeOnPrimaryStorage = pd.create(volume);
|
DataObject volumeOnPrimaryStorage = pd.create(volume, volume.getDeployAsIsConfiguration());
|
||||||
volumeOnPrimaryStorage.processEvent(Event.CreateOnlyRequested);
|
volumeOnPrimaryStorage.processEvent(Event.CreateOnlyRequested);
|
||||||
|
|
||||||
CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(null, volumeOnPrimaryStorage, pd, templateOnPrimaryStore, future, null);
|
CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(null, volumeOnPrimaryStorage, pd, templateOnPrimaryStore, future, null, volume.getDeployAsIsConfiguration());
|
||||||
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
|
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
|
||||||
caller.setCallback(caller.getTarget().createVolumeFromBaseImageCallBack(null, null));
|
caller.setCallback(caller.getTarget().createVolumeFromBaseImageCallBack(null, null));
|
||||||
caller.setContext(context);
|
caller.setContext(context);
|
||||||
|
|
||||||
motionSrv.copyAsync(context.templateOnStore, volumeOnPrimaryStorage, caller);
|
motionSrv.copyAsync(context.templateOnStore, volumeOnPrimaryStorage, caller);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -740,6 +746,7 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
DataObject tmplOnPrimary = context.templateOnStore;
|
DataObject tmplOnPrimary = context.templateOnStore;
|
||||||
CopyCommandResult result = callback.getResult();
|
CopyCommandResult result = callback.getResult();
|
||||||
VolumeApiResult volResult = new VolumeApiResult((VolumeObject)vo);
|
VolumeApiResult volResult = new VolumeApiResult((VolumeObject)vo);
|
||||||
|
String deployAsIsConfiguration = context.deployAsIsConfiguration;
|
||||||
|
|
||||||
if (result.isSuccess()) {
|
if (result.isSuccess()) {
|
||||||
vo.processEvent(Event.OperationSuccessed, result.getAnswer());
|
vo.processEvent(Event.OperationSuccessed, result.getAnswer());
|
||||||
@ -750,10 +757,10 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
// hack for Vmware: host is down, previously download template to the host needs to be re-downloaded, so we need to reset
|
// hack for Vmware: host is down, previously download template to the host needs to be re-downloaded, so we need to reset
|
||||||
// template_spool_ref entry here to NOT_DOWNLOADED and Allocated state
|
// template_spool_ref entry here to NOT_DOWNLOADED and Allocated state
|
||||||
Answer ans = result.getAnswer();
|
Answer ans = result.getAnswer();
|
||||||
if (ans != null && ans instanceof CopyCmdAnswer && ans.getDetails().contains("request template reload")) {
|
if (ans != null && ans instanceof CopyCmdAnswer && ans.getDetails().contains(REQUEST_TEMPLATE_RELOAD)) {
|
||||||
if (tmplOnPrimary != null) {
|
if (tmplOnPrimary != null) {
|
||||||
s_logger.info("Reset template_spool_ref entry so that vmware template can be reloaded in next try");
|
s_logger.info("Reset template_spool_ref entry so that vmware template can be reloaded in next try");
|
||||||
VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(tmplOnPrimary.getDataStore().getId(), tmplOnPrimary.getId());
|
VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(tmplOnPrimary.getDataStore().getId(), tmplOnPrimary.getId(), deployAsIsConfiguration);
|
||||||
if (templatePoolRef != null) {
|
if (templatePoolRef != null) {
|
||||||
long templatePoolRefId = templatePoolRef.getId();
|
long templatePoolRefId = templatePoolRef.getId();
|
||||||
templatePoolRef = _tmpltPoolDao.acquireInLockTable(templatePoolRefId, 1200);
|
templatePoolRef = _tmpltPoolDao.acquireInLockTable(templatePoolRefId, 1200);
|
||||||
@ -789,9 +796,9 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
private TemplateInfo createManagedTemplateVolume(TemplateInfo srcTemplateInfo, PrimaryDataStore destPrimaryDataStore) {
|
private TemplateInfo createManagedTemplateVolume(TemplateInfo srcTemplateInfo, PrimaryDataStore destPrimaryDataStore) {
|
||||||
// create a template volume on primary storage
|
// create a template volume on primary storage
|
||||||
AsyncCallFuture<VolumeApiResult> createTemplateFuture = new AsyncCallFuture<>();
|
AsyncCallFuture<VolumeApiResult> createTemplateFuture = new AsyncCallFuture<>();
|
||||||
TemplateInfo templateOnPrimary = (TemplateInfo)destPrimaryDataStore.create(srcTemplateInfo);
|
TemplateInfo templateOnPrimary = (TemplateInfo)destPrimaryDataStore.create(srcTemplateInfo, srcTemplateInfo.getDeployAsIsConfiguration());
|
||||||
|
|
||||||
VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(destPrimaryDataStore.getId(), templateOnPrimary.getId());
|
VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(destPrimaryDataStore.getId(), templateOnPrimary.getId(), srcTemplateInfo.getDeployAsIsConfiguration());
|
||||||
|
|
||||||
if (templatePoolRef == null) {
|
if (templatePoolRef == null) {
|
||||||
throw new CloudRuntimeException("Failed to find template " + srcTemplateInfo.getUniqueName() + " in storage pool " + destPrimaryDataStore.getId());
|
throw new CloudRuntimeException("Failed to find template " + srcTemplateInfo.getUniqueName() + " in storage pool " + destPrimaryDataStore.getId());
|
||||||
@ -986,7 +993,7 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
* @param future For async
|
* @param future For async
|
||||||
*/
|
*/
|
||||||
private void createManagedVolumeCloneTemplateAsync(VolumeInfo volumeInfo, TemplateInfo templateOnPrimary, PrimaryDataStore destPrimaryDataStore, AsyncCallFuture<VolumeApiResult> future) {
|
private void createManagedVolumeCloneTemplateAsync(VolumeInfo volumeInfo, TemplateInfo templateOnPrimary, PrimaryDataStore destPrimaryDataStore, AsyncCallFuture<VolumeApiResult> future) {
|
||||||
VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(destPrimaryDataStore.getId(), templateOnPrimary.getId());
|
VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(destPrimaryDataStore.getId(), templateOnPrimary.getId(), volumeInfo.getDeployAsIsConfiguration());
|
||||||
|
|
||||||
if (templatePoolRef == null) {
|
if (templatePoolRef == null) {
|
||||||
throw new CloudRuntimeException("Failed to find template " + templateOnPrimary.getUniqueName() + " in storage pool " + destPrimaryDataStore.getId());
|
throw new CloudRuntimeException("Failed to find template " + templateOnPrimary.getUniqueName() + " in storage pool " + destPrimaryDataStore.getId());
|
||||||
@ -1000,7 +1007,7 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
try {
|
try {
|
||||||
volumeInfo.processEvent(Event.CreateOnlyRequested);
|
volumeInfo.processEvent(Event.CreateOnlyRequested);
|
||||||
|
|
||||||
CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<>(null, volumeInfo, destPrimaryDataStore, templateOnPrimary, future, null);
|
CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<>(null, volumeInfo, destPrimaryDataStore, templateOnPrimary, future, null, volumeInfo.getDeployAsIsConfiguration());
|
||||||
|
|
||||||
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
|
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
|
||||||
|
|
||||||
@ -1021,7 +1028,7 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
try {
|
try {
|
||||||
// Create a volume on managed storage.
|
// Create a volume on managed storage.
|
||||||
|
|
||||||
TemplateInfo destTemplateInfo = (TemplateInfo)primaryDataStore.create(srcTemplateInfo, false);
|
TemplateInfo destTemplateInfo = (TemplateInfo)primaryDataStore.create(srcTemplateInfo, false, volumeInfo.getDeployAsIsConfiguration());
|
||||||
|
|
||||||
AsyncCallFuture<VolumeApiResult> createVolumeFuture = createVolumeAsync(volumeInfo, primaryDataStore);
|
AsyncCallFuture<VolumeApiResult> createVolumeFuture = createVolumeAsync(volumeInfo, primaryDataStore);
|
||||||
VolumeApiResult createVolumeResult = createVolumeFuture.get();
|
VolumeApiResult createVolumeResult = createVolumeFuture.get();
|
||||||
@ -1109,7 +1116,7 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
if (storageCanCloneVolume && computeSupportsVolumeClone) {
|
if (storageCanCloneVolume && computeSupportsVolumeClone) {
|
||||||
s_logger.debug("Storage " + destDataStoreId + " can support cloning using a cached template and compute side is OK with volume cloning.");
|
s_logger.debug("Storage " + destDataStoreId + " can support cloning using a cached template and compute side is OK with volume cloning.");
|
||||||
|
|
||||||
TemplateInfo templateOnPrimary = destPrimaryDataStore.getTemplate(srcTemplateInfo.getId());
|
TemplateInfo templateOnPrimary = destPrimaryDataStore.getTemplate(srcTemplateInfo.getId(), null);
|
||||||
|
|
||||||
if (templateOnPrimary == null) {
|
if (templateOnPrimary == null) {
|
||||||
templateOnPrimary = createManagedTemplateVolume(srcTemplateInfo, destPrimaryDataStore);
|
templateOnPrimary = createManagedTemplateVolume(srcTemplateInfo, destPrimaryDataStore);
|
||||||
@ -1120,7 +1127,7 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy the template to the template volume.
|
// Copy the template to the template volume.
|
||||||
VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(destPrimaryDataStore.getId(), templateOnPrimary.getId());
|
VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(destPrimaryDataStore.getId(), templateOnPrimary.getId(), null);
|
||||||
|
|
||||||
if (templatePoolRef == null) {
|
if (templatePoolRef == null) {
|
||||||
throw new CloudRuntimeException("Failed to find template " + srcTemplateInfo.getUniqueName() + " in storage pool " + destPrimaryDataStore.getId());
|
throw new CloudRuntimeException("Failed to find template " + srcTemplateInfo.getUniqueName() + " in storage pool " + destPrimaryDataStore.getId());
|
||||||
@ -1196,8 +1203,8 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
@Override
|
@Override
|
||||||
public AsyncCallFuture<VolumeApiResult> createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId, TemplateInfo template) {
|
public AsyncCallFuture<VolumeApiResult> createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId, TemplateInfo template) {
|
||||||
PrimaryDataStore pd = dataStoreMgr.getPrimaryDataStore(dataStoreId);
|
PrimaryDataStore pd = dataStoreMgr.getPrimaryDataStore(dataStoreId);
|
||||||
TemplateInfo templateOnPrimaryStore = pd.getTemplate(template.getId());
|
TemplateInfo templateOnPrimaryStore = pd.getTemplate(template.getId(), volume.getDeployAsIsConfiguration());
|
||||||
AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
|
AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<>();
|
||||||
|
|
||||||
if (templateOnPrimaryStore == null) {
|
if (templateOnPrimaryStore == null) {
|
||||||
createBaseImageAsync(volume, pd, template, future);
|
createBaseImageAsync(volume, pd, template, future);
|
||||||
@ -1234,7 +1241,7 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
volumeOnStore.processEvent(Event.CreateOnlyRequested);
|
volumeOnStore.processEvent(Event.CreateOnlyRequested);
|
||||||
_volumeDetailsDao.addDetail(volume.getId(), SNAPSHOT_ID, Long.toString(snapshot.getId()), false);
|
_volumeDetailsDao.addDetail(volume.getId(), SNAPSHOT_ID, Long.toString(snapshot.getId()), false);
|
||||||
|
|
||||||
CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(null, volume, store, volumeOnStore, future, snapshot);
|
CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(null, volume, store, volumeOnStore, future, snapshot, null);
|
||||||
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
|
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
|
||||||
caller.setCallback(caller.getTarget().createVolumeFromSnapshotCallback(null, null)).setContext(context);
|
caller.setCallback(caller.getTarget().createVolumeFromSnapshotCallback(null, null)).setContext(context);
|
||||||
motionSrv.copyAsync(snapshot, volumeOnStore, caller);
|
motionSrv.copyAsync(snapshot, volumeOnStore, caller);
|
||||||
|
|||||||
@ -598,7 +598,7 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
private VMTemplateVO createVMTemplateRecord(String vmInternalName, long guestOsId, long accountId) {
|
private VMTemplateVO createVMTemplateRecord(String vmInternalName, long guestOsId, long accountId) {
|
||||||
Long nextTemplateId = vmTemplateDao.getNextInSequence(Long.class, "id");
|
Long nextTemplateId = vmTemplateDao.getNextInSequence(Long.class, "id");
|
||||||
VMTemplateVO templateVO = new VMTemplateVO(nextTemplateId, "Imported-from-" + vmInternalName, Storage.ImageFormat.OVA, false, false, false, Storage.TemplateType.USER, null,
|
VMTemplateVO templateVO = new VMTemplateVO(nextTemplateId, "Imported-from-" + vmInternalName, Storage.ImageFormat.OVA, false, false, false, Storage.TemplateType.USER, null,
|
||||||
false, 64, accountId, null, "Template imported from VM " + vmInternalName, false, guestOsId, false, HypervisorType.VMware, null, null, false, false, false);
|
false, 64, accountId, null, "Template imported from VM " + vmInternalName, false, guestOsId, false, HypervisorType.VMware, null, null, false, false, false, false);
|
||||||
return vmTemplateDao.persist(templateVO);
|
return vmTemplateDao.persist(templateVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -619,7 +619,7 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
VMTemplateStoragePoolVO templateRef = templateStoragePoolDao.findByPoolPath(poolId, templatePath);
|
VMTemplateStoragePoolVO templateRef = templateStoragePoolDao.findByPoolPath(poolId, templatePath);
|
||||||
if (templateRef == null) {
|
if (templateRef == null) {
|
||||||
templateRef = new VMTemplateStoragePoolVO(poolId, templateId, null, 100, VMTemplateStorageResourceAssoc.Status.DOWNLOADED, templatePath, null, null, templatePath,
|
templateRef = new VMTemplateStoragePoolVO(poolId, templateId, null, 100, VMTemplateStorageResourceAssoc.Status.DOWNLOADED, templatePath, null, null, templatePath,
|
||||||
templateSize);
|
templateSize, null);
|
||||||
templateRef.setState(ObjectInDataStoreStateMachine.State.Ready);
|
templateRef.setState(ObjectInDataStoreStateMachine.State.Ready);
|
||||||
templateStoragePoolDao.persist(templateRef);
|
templateStoragePoolDao.persist(templateRef);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
package com.cloud.hypervisor.guru;
|
package com.cloud.hypervisor.guru;
|
||||||
|
|
||||||
import com.cloud.agent.api.storage.OVFPropertyTO;
|
import com.cloud.agent.api.storage.OVFPropertyTO;
|
||||||
import com.cloud.agent.api.to.DataStoreTO;
|
import com.cloud.agent.api.to.DeployAsIsInfoTO;
|
||||||
import com.cloud.agent.api.to.DiskTO;
|
import com.cloud.agent.api.to.DiskTO;
|
||||||
import com.cloud.agent.api.to.NicTO;
|
import com.cloud.agent.api.to.NicTO;
|
||||||
import com.cloud.agent.api.to.VirtualMachineTO;
|
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||||
@ -35,16 +35,14 @@ import com.cloud.network.dao.NetworkDao;
|
|||||||
import com.cloud.network.dao.NetworkVO;
|
import com.cloud.network.dao.NetworkVO;
|
||||||
import com.cloud.storage.GuestOSHypervisorVO;
|
import com.cloud.storage.GuestOSHypervisorVO;
|
||||||
import com.cloud.storage.GuestOSVO;
|
import com.cloud.storage.GuestOSVO;
|
||||||
import com.cloud.storage.TemplateOVFPropertyVO;
|
import com.cloud.storage.ImageStore;
|
||||||
import com.cloud.storage.VMTemplateStoragePoolVO;
|
import com.cloud.storage.VMTemplateStoragePoolVO;
|
||||||
import com.cloud.storage.VMTemplateStorageResourceAssoc;
|
|
||||||
import com.cloud.storage.Volume;
|
import com.cloud.storage.Volume;
|
||||||
import com.cloud.storage.dao.GuestOSDao;
|
import com.cloud.storage.dao.GuestOSDao;
|
||||||
import com.cloud.storage.dao.GuestOSHypervisorDao;
|
import com.cloud.storage.dao.GuestOSHypervisorDao;
|
||||||
import com.cloud.storage.dao.TemplateOVFPropertiesDao;
|
import com.cloud.storage.dao.VMTemplateDetailsDao;
|
||||||
import com.cloud.storage.dao.VMTemplatePoolDao;
|
import com.cloud.storage.dao.VMTemplatePoolDao;
|
||||||
import com.cloud.template.VirtualMachineTemplate;
|
import com.cloud.template.VirtualMachineTemplate;
|
||||||
import com.cloud.utils.Pair;
|
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import com.cloud.vm.DomainRouterVO;
|
import com.cloud.vm.DomainRouterVO;
|
||||||
import com.cloud.vm.NicProfile;
|
import com.cloud.vm.NicProfile;
|
||||||
@ -70,7 +68,7 @@ import java.util.Map;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
class VmwareVmImplementer {
|
class VmwareVmImplementer {
|
||||||
private static final Logger LOG = Logger.getLogger(VmwareVmImplementer.class);
|
private static final Logger LOGGER = Logger.getLogger(VmwareVmImplementer.class);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
DomainRouterDao domainRouterDao;
|
DomainRouterDao domainRouterDao;
|
||||||
@ -89,10 +87,10 @@ class VmwareVmImplementer {
|
|||||||
@Inject
|
@Inject
|
||||||
PrimaryDataStoreDao storagePoolDao;
|
PrimaryDataStoreDao storagePoolDao;
|
||||||
@Inject
|
@Inject
|
||||||
TemplateOVFPropertiesDao templateOVFPropertiesDao;
|
|
||||||
@Inject
|
|
||||||
VMTemplatePoolDao templateStoragePoolDao;
|
VMTemplatePoolDao templateStoragePoolDao;
|
||||||
@Inject
|
@Inject
|
||||||
|
VMTemplateDetailsDao templateDetailsDao;
|
||||||
|
@Inject
|
||||||
VmwareManager vmwareMgr;
|
VmwareManager vmwareMgr;
|
||||||
|
|
||||||
private Boolean globalNestedVirtualisationEnabled;
|
private Boolean globalNestedVirtualisationEnabled;
|
||||||
@ -116,10 +114,11 @@ class VmwareVmImplementer {
|
|||||||
|
|
||||||
VirtualMachineTO implement(VirtualMachineProfile vm, VirtualMachineTO to, long clusterId) {
|
VirtualMachineTO implement(VirtualMachineProfile vm, VirtualMachineTO to, long clusterId) {
|
||||||
to.setBootloader(VirtualMachineTemplate.BootloaderType.HVM);
|
to.setBootloader(VirtualMachineTemplate.BootloaderType.HVM);
|
||||||
|
boolean deployAsIs = vm.getTemplate().isDeployAsIs();
|
||||||
|
HostVO host = hostDao.findById(vm.getVirtualMachine().getHostId());
|
||||||
Map<String, String> details = to.getDetails();
|
Map<String, String> details = to.getDetails();
|
||||||
if (details == null)
|
if (details == null)
|
||||||
details = new HashMap<String, String>();
|
details = new HashMap<>();
|
||||||
|
|
||||||
VirtualMachine.Type vmType = vm.getType();
|
VirtualMachine.Type vmType = vm.getType();
|
||||||
boolean userVm = !(vmType.equals(VirtualMachine.Type.DomainRouter) || vmType.equals(VirtualMachine.Type.ConsoleProxy) || vmType.equals(VirtualMachine.Type.SecondaryStorageVm));
|
boolean userVm = !(vmType.equals(VirtualMachine.Type.DomainRouter) || vmType.equals(VirtualMachine.Type.ConsoleProxy) || vmType.equals(VirtualMachine.Type.SecondaryStorageVm));
|
||||||
@ -133,7 +132,7 @@ class VmwareVmImplementer {
|
|||||||
try {
|
try {
|
||||||
VirtualEthernetCardType.valueOf(nicDeviceType);
|
VirtualEthernetCardType.valueOf(nicDeviceType);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.warn("Invalid NIC device type " + nicDeviceType + " is specified in VM details, switch to default E1000");
|
LOGGER.warn("Invalid NIC device type " + nicDeviceType + " is specified in VM details, switch to default E1000");
|
||||||
details.put(VmDetailConstants.NIC_ADAPTER, VirtualEthernetCardType.E1000.toString());
|
details.put(VmDetailConstants.NIC_ADAPTER, VirtualEthernetCardType.E1000.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,7 +144,7 @@ class VmwareVmImplementer {
|
|||||||
try {
|
try {
|
||||||
VirtualEthernetCardType.valueOf(nicDeviceType);
|
VirtualEthernetCardType.valueOf(nicDeviceType);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.warn("Invalid NIC device type " + nicDeviceType + " is specified in VM details, switch to default E1000");
|
LOGGER.warn("Invalid NIC device type " + nicDeviceType + " is specified in VM details, switch to default E1000");
|
||||||
details.put(VmDetailConstants.NIC_ADAPTER, VirtualEthernetCardType.E1000.toString());
|
details.put(VmDetailConstants.NIC_ADAPTER, VirtualEthernetCardType.E1000.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -172,7 +171,7 @@ class VmwareVmImplementer {
|
|||||||
GuestOSVO guestOS = guestOsDao.findByIdIncludingRemoved(vm.getVirtualMachine().getGuestOSId());
|
GuestOSVO guestOS = guestOsDao.findByIdIncludingRemoved(vm.getVirtualMachine().getGuestOSId());
|
||||||
to.setOs(guestOS.getDisplayName());
|
to.setOs(guestOS.getDisplayName());
|
||||||
to.setHostName(vm.getHostName());
|
to.setHostName(vm.getHostName());
|
||||||
HostVO host = hostDao.findById(vm.getVirtualMachine().getHostId());
|
|
||||||
GuestOSHypervisorVO guestOsMapping = null;
|
GuestOSHypervisorVO guestOsMapping = null;
|
||||||
if (host != null) {
|
if (host != null) {
|
||||||
guestOsMapping = guestOsHypervisorDao.findByOsIdAndHypervisor(guestOS.getId(), Hypervisor.HypervisorType.VMware.toString(), host.getHypervisorVersion());
|
guestOsMapping = guestOsHypervisorDao.findByOsIdAndHypervisor(guestOS.getId(), Hypervisor.HypervisorType.VMware.toString(), host.getHypervisorVersion());
|
||||||
@ -183,22 +182,55 @@ class VmwareVmImplementer {
|
|||||||
to.setPlatformEmulator(guestOsMapping.getGuestOsName());
|
to.setPlatformEmulator(guestOsMapping.getGuestOsName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (deployAsIs) {
|
||||||
List<OVFPropertyTO> ovfProperties = getOvfPropertyList(vm, details);
|
List<OVFPropertyTO> ovfProperties = getOvfPropertyList(vm, details);
|
||||||
|
|
||||||
handleOvfProperties(vm, to, details, ovfProperties);
|
handleOvfProperties(vm, to, details, ovfProperties);
|
||||||
|
setDeployAsIsParams(vm, to, details);
|
||||||
|
}
|
||||||
|
|
||||||
setDetails(to, details);
|
setDetails(to, details);
|
||||||
|
|
||||||
return to;
|
return to;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setDeployAsIsParams(VirtualMachineProfile vm, VirtualMachineTO to, Map<String, String> details) {
|
||||||
|
DeployAsIsInfoTO info = new DeployAsIsInfoTO();
|
||||||
|
|
||||||
|
String configuration = null;
|
||||||
|
if (details.containsKey(VmDetailConstants.DEPLOY_AS_IS_CONFIGURATION)) {
|
||||||
|
configuration = details.get(VmDetailConstants.DEPLOY_AS_IS_CONFIGURATION);
|
||||||
|
info.setDeploymentConfiguration(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deploy as-is disks are all allocated to the same storage pool
|
||||||
|
String deployAsIsStoreUuid = vm.getDisks().get(0).getData().getDataStore().getUuid();
|
||||||
|
StoragePoolVO storagePoolVO = storagePoolDao.findByUuid(deployAsIsStoreUuid);
|
||||||
|
VMTemplateStoragePoolVO tmplRef = templateStoragePoolDao.findByPoolTemplate(storagePoolVO.getId(), vm.getTemplate().getId(), configuration);
|
||||||
|
if (tmplRef != null) {
|
||||||
|
info.setTemplatePath(tmplRef.getInstallPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
info.setDeployAsIs(true);
|
||||||
|
to.setDeployAsIsInfo(info);
|
||||||
|
}
|
||||||
|
|
||||||
private void setDetails(VirtualMachineTO to, Map<String, String> details) {
|
private void setDetails(VirtualMachineTO to, Map<String, String> details) {
|
||||||
if (LOG.isTraceEnabled()) {
|
Map<String, String> detailsToSend = new HashMap<>();
|
||||||
for (String key: details.keySet()) {
|
for (String key: details.keySet()) {
|
||||||
LOG.trace(String.format("Detail for VM %s: %s => %s",to.getName(), key, details.get(key)));
|
if (key.startsWith(ImageStore.OVF_EULA_SECTION_PREFIX) ||
|
||||||
|
key.startsWith(ImageStore.OVF_HARDWARE_CONFIGURATION_PREFIX) ||
|
||||||
|
key.startsWith(ImageStore.OVF_HARDWARE_ITEM_PREFIX)) {
|
||||||
|
if (LOGGER.isTraceEnabled()) {
|
||||||
|
LOGGER.trace(String.format("Discarding detail for VM %s: %s => %s", to.getName(), key, details.get(key)));
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
to.setDetails(details);
|
if (LOGGER.isTraceEnabled()) {
|
||||||
|
LOGGER.trace(String.format("Detail for VM %s: %s => %s", to.getName(), key, details.get(key)));
|
||||||
|
}
|
||||||
|
detailsToSend.put(key, details.get(key));
|
||||||
|
}
|
||||||
|
to.setDetails(detailsToSend);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void configureDomainRouterNicsAndDetails(VirtualMachineProfile vm, VirtualMachineTO to, Map<String, String> details, List<NicProfile> nicProfiles) {
|
private void configureDomainRouterNicsAndDetails(VirtualMachineProfile vm, VirtualMachineTO to, Map<String, String> details, List<NicProfile> nicProfiles) {
|
||||||
@ -289,47 +321,40 @@ class VmwareVmImplementer {
|
|||||||
private void handleOvfProperties(VirtualMachineProfile vm, VirtualMachineTO to, Map<String, String> details, List<OVFPropertyTO> ovfProperties) {
|
private void handleOvfProperties(VirtualMachineProfile vm, VirtualMachineTO to, Map<String, String> details, List<OVFPropertyTO> ovfProperties) {
|
||||||
if (CollectionUtils.isNotEmpty(ovfProperties)) {
|
if (CollectionUtils.isNotEmpty(ovfProperties)) {
|
||||||
removeOvfPropertiesFromDetails(ovfProperties, details);
|
removeOvfPropertiesFromDetails(ovfProperties, details);
|
||||||
String templateInstallPath = null;
|
to.setOvfProperties(ovfProperties);
|
||||||
List<DiskTO> rootDiskList = vm.getDisks().stream().filter(x -> x.getType() == Volume.Type.ROOT).collect(Collectors.toList());
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DiskTO getRootDiskTOFromVM(VirtualMachineProfile vm) {
|
||||||
|
DiskTO rootDiskTO;
|
||||||
|
List<DiskTO> rootDiskList;
|
||||||
|
rootDiskList = vm.getDisks().stream().filter(x -> x.getType() == Volume.Type.ROOT).collect(Collectors.toList());
|
||||||
if (rootDiskList.size() != 1) {
|
if (rootDiskList.size() != 1) {
|
||||||
|
if (vm.getTemplate().isDeployAsIs()) {
|
||||||
|
rootDiskList = vm.getDisks().stream().filter(x -> x.getType() == null).collect(Collectors.toList());
|
||||||
|
if (rootDiskList.size() < 1) {
|
||||||
|
throw new CloudRuntimeException("Did not find a template to serve as root disk for VM " + vm.getHostName());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
throw new CloudRuntimeException("Did not find only one root disk for VM " + vm.getHostName());
|
throw new CloudRuntimeException("Did not find only one root disk for VM " + vm.getHostName());
|
||||||
}
|
}
|
||||||
|
|
||||||
DiskTO rootDiskTO = rootDiskList.get(0);
|
|
||||||
DataStoreTO dataStore = rootDiskTO.getData().getDataStore();
|
|
||||||
StoragePoolVO storagePoolVO = storagePoolDao.findByUuid(dataStore.getUuid());
|
|
||||||
long dataCenterId = storagePoolVO.getDataCenterId();
|
|
||||||
List<StoragePoolVO> pools = storagePoolDao.listByDataCenterId(dataCenterId);
|
|
||||||
for (StoragePoolVO pool : pools) {
|
|
||||||
VMTemplateStoragePoolVO ref = templateStoragePoolDao.findByPoolTemplate(pool.getId(), vm.getTemplateId());
|
|
||||||
if (ref != null && ref.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) {
|
|
||||||
templateInstallPath = ref.getInstallPath();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (templateInstallPath == null) {
|
|
||||||
throw new CloudRuntimeException("Did not find the template install path for template " + vm.getTemplateId() + " on zone " + dataCenterId);
|
|
||||||
}
|
|
||||||
|
|
||||||
Pair<String, List<OVFPropertyTO>> pair = new Pair<String, List<OVFPropertyTO>>(templateInstallPath, ovfProperties);
|
|
||||||
to.setOvfProperties(pair);
|
|
||||||
}
|
}
|
||||||
|
rootDiskTO = rootDiskList.get(0);
|
||||||
|
return rootDiskTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<OVFPropertyTO> getOvfPropertyList(VirtualMachineProfile vm, Map<String, String> details) {
|
private List<OVFPropertyTO> getOvfPropertyList(VirtualMachineProfile vm, Map<String, String> details) {
|
||||||
List<OVFPropertyTO> ovfProperties = new ArrayList<OVFPropertyTO>();
|
List<OVFPropertyTO> ovfProperties = new ArrayList<OVFPropertyTO>();
|
||||||
for (String detailKey : details.keySet()) {
|
for (String detailKey : details.keySet()) {
|
||||||
if (detailKey.startsWith(ApiConstants.OVF_PROPERTIES)) {
|
if (detailKey.startsWith(ImageStore.ACS_PROPERTY_PREFIX)) {
|
||||||
String ovfPropKey = detailKey.replace(ApiConstants.OVF_PROPERTIES + "-", "");
|
OVFPropertyTO propertyTO = templateDetailsDao.findPropertyByTemplateAndKey(vm.getTemplateId(), detailKey);
|
||||||
TemplateOVFPropertyVO templateOVFPropertyVO = templateOVFPropertiesDao.findByTemplateAndKey(vm.getTemplateId(), ovfPropKey);
|
String vmPropertyKey = detailKey.replace(ImageStore.ACS_PROPERTY_PREFIX, "");
|
||||||
if (templateOVFPropertyVO == null) {
|
if (propertyTO == null) {
|
||||||
LOG.warn(String.format("OVF property %s not found on template, discarding", ovfPropKey));
|
LOGGER.warn(String.format("OVF property %s not found on template, discarding", vmPropertyKey));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
String ovfValue = details.get(detailKey);
|
propertyTO.setKey(vmPropertyKey);
|
||||||
boolean isPassword = templateOVFPropertyVO.isPassword();
|
propertyTO.setValue(details.get(detailKey));
|
||||||
OVFPropertyTO propertyTO = new OVFPropertyTO(ovfPropKey, ovfValue, isPassword);
|
|
||||||
ovfProperties.add(propertyTO);
|
ovfProperties.add(propertyTO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -389,7 +414,7 @@ class VmwareVmImplementer {
|
|||||||
private void removeOvfPropertiesFromDetails(List<OVFPropertyTO> ovfProperties, Map<String, String> details) {
|
private void removeOvfPropertiesFromDetails(List<OVFPropertyTO> ovfProperties, Map<String, String> details) {
|
||||||
for (OVFPropertyTO propertyTO : ovfProperties) {
|
for (OVFPropertyTO propertyTO : ovfProperties) {
|
||||||
String key = propertyTO.getKey();
|
String key = propertyTO.getKey();
|
||||||
details.remove(ApiConstants.OVF_PROPERTIES + "-" + key);
|
details.remove(ApiConstants.PROPERTIES + "-" + key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,8 +430,8 @@ class VmwareVmImplementer {
|
|||||||
Boolean globalNestedVPerVMEnabled = getGlobalNestedVPerVMEnabled();
|
Boolean globalNestedVPerVMEnabled = getGlobalNestedVPerVMEnabled();
|
||||||
|
|
||||||
Boolean shouldEnableNestedVirtualization = shouldEnableNestedVirtualization(globalNestedVirtualisationEnabled, globalNestedVPerVMEnabled, localNestedV);
|
Boolean shouldEnableNestedVirtualization = shouldEnableNestedVirtualization(globalNestedVirtualisationEnabled, globalNestedVPerVMEnabled, localNestedV);
|
||||||
if(LOG.isDebugEnabled()) {
|
if(LOGGER.isDebugEnabled()) {
|
||||||
LOG.debug(String.format(
|
LOGGER.debug(String.format(
|
||||||
"Due to '%B'(globalNestedVirtualisationEnabled) and '%B'(globalNestedVPerVMEnabled) I'm adding a flag with value %B to the vm configuration for Nested Virtualisation.",
|
"Due to '%B'(globalNestedVirtualisationEnabled) and '%B'(globalNestedVPerVMEnabled) I'm adding a flag with value %B to the vm configuration for Nested Virtualisation.",
|
||||||
globalNestedVirtualisationEnabled,
|
globalNestedVirtualisationEnabled,
|
||||||
globalNestedVPerVMEnabled,
|
globalNestedVPerVMEnabled,
|
||||||
|
|||||||
@ -591,7 +591,7 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String vmName = templateUuid;
|
String vmName = templateUuid;
|
||||||
hyperHost.importVmFromOVF(srcFileName, vmName, datastoreMo, "thin");
|
hyperHost.importVmFromOVF(srcFileName, vmName, datastoreMo, "thin", null);
|
||||||
|
|
||||||
VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmName);
|
VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmName);
|
||||||
if (vmMo == null) {
|
if (vmMo == null) {
|
||||||
@ -912,7 +912,7 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager {
|
|||||||
|
|
||||||
VirtualMachineMO clonedVm = null;
|
VirtualMachineMO clonedVm = null;
|
||||||
try {
|
try {
|
||||||
hyperHost.importVmFromOVF(srcOVFFileName, newVolumeName, primaryDsMo, "thin");
|
hyperHost.importVmFromOVF(srcOVFFileName, newVolumeName, primaryDsMo, "thin", null);
|
||||||
clonedVm = hyperHost.findVmOnHyperHost(newVolumeName);
|
clonedVm = hyperHost.findVmOnHyperHost(newVolumeName);
|
||||||
if (clonedVm == null) {
|
if (clonedVm == null) {
|
||||||
throw new Exception("Unable to create container VM for volume creation");
|
throw new Exception("Unable to create container VM for volume creation");
|
||||||
|
|||||||
@ -16,10 +16,53 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.hypervisor.vmware.resource;
|
package com.cloud.hypervisor.vmware.resource;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.ConnectException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.rmi.RemoteException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.naming.ConfigurationException;
|
||||||
|
import javax.xml.datatype.XMLGregorianCalendar;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.to.DataTO;
|
||||||
|
import com.cloud.agent.api.to.DeployAsIsInfoTO;
|
||||||
|
import com.cloud.storage.ImageStore;
|
||||||
import com.cloud.agent.api.ValidateVcenterDetailsCommand;
|
import com.cloud.agent.api.ValidateVcenterDetailsCommand;
|
||||||
import org.apache.cloudstack.api.ApiConstants;
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
import org.apache.cloudstack.storage.configdrive.ConfigDrive;
|
import org.apache.cloudstack.storage.configdrive.ConfigDrive;
|
||||||
import org.apache.cloudstack.storage.to.TemplateObjectTO;
|
import org.apache.cloudstack.storage.to.TemplateObjectTO;
|
||||||
|
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
||||||
|
import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
|
||||||
|
import org.apache.cloudstack.vm.UnmanagedInstanceTO;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.apache.commons.collections.MapUtils;
|
||||||
|
import org.apache.commons.lang.ArrayUtils;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.commons.lang.math.NumberUtils;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
import org.apache.log4j.NDC;
|
||||||
|
import org.joda.time.Duration;
|
||||||
|
|
||||||
import com.cloud.agent.IAgentControl;
|
import com.cloud.agent.IAgentControl;
|
||||||
import com.cloud.agent.api.Answer;
|
import com.cloud.agent.api.Answer;
|
||||||
@ -1796,6 +1839,21 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
s_logger.error(msg);
|
s_logger.error(msg);
|
||||||
throw new Exception(msg);
|
throw new Exception(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DiskTO[] specDisks = vmSpec.getDisks();
|
||||||
|
DeployAsIsInfoTO deployAsIsInfo = vmSpec.getDeployAsIsInfo();
|
||||||
|
boolean installAsIs = deployAsIsInfo != null && deployAsIsInfo.isDeployAsIs();
|
||||||
|
if (installAsIs && dcMo.findVm(vmInternalCSName) == null) {
|
||||||
|
if (s_logger.isTraceEnabled()) {
|
||||||
|
s_logger.trace("Deploying OVA from as is");
|
||||||
|
}
|
||||||
|
String deployAsIsTemplate = deployAsIsInfo.getTemplatePath();
|
||||||
|
String destDatastore = getDatastoreFromSpecDisks(specDisks);
|
||||||
|
String deploymentConfiguration = deployAsIsInfo.getDeploymentConfiguration();
|
||||||
|
vmInVcenter = _storageProcessor.cloneVMFromTemplate(deployAsIsTemplate, vmInternalCSName, destDatastore);
|
||||||
|
mapSpecDisksToClonedDisks(vmInVcenter, vmInternalCSName, specDisks);
|
||||||
|
}
|
||||||
|
|
||||||
String guestOsId = translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs(), vmSpec.getPlatformEmulator()).value();
|
String guestOsId = translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs(), vmSpec.getPlatformEmulator()).value();
|
||||||
DiskTO[] disks = validateDisks(vmSpec.getDisks());
|
DiskTO[] disks = validateDisks(vmSpec.getDisks());
|
||||||
assert (disks.length > 0);
|
assert (disks.length > 0);
|
||||||
@ -1816,6 +1874,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
}
|
}
|
||||||
|
|
||||||
VirtualMachineDiskInfoBuilder diskInfoBuilder = null;
|
VirtualMachineDiskInfoBuilder diskInfoBuilder = null;
|
||||||
|
VirtualDevice[] nicDevices = null;
|
||||||
VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmInternalCSName);
|
VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmInternalCSName);
|
||||||
DiskControllerType systemVmScsiControllerType = DiskControllerType.lsilogic;
|
DiskControllerType systemVmScsiControllerType = DiskControllerType.lsilogic;
|
||||||
int firstScsiControllerBusNum = 0;
|
int firstScsiControllerBusNum = 0;
|
||||||
@ -1829,6 +1888,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
// retrieve disk information before we tear down
|
// retrieve disk information before we tear down
|
||||||
diskInfoBuilder = vmMo.getDiskInfoBuilder();
|
diskInfoBuilder = vmMo.getDiskInfoBuilder();
|
||||||
hasSnapshot = vmMo.hasSnapshot();
|
hasSnapshot = vmMo.hasSnapshot();
|
||||||
|
nicDevices = vmMo.getNicDevices();
|
||||||
if (!hasSnapshot)
|
if (!hasSnapshot)
|
||||||
vmMo.tearDownDevices(new Class<?>[]{VirtualDisk.class, VirtualEthernetCard.class});
|
vmMo.tearDownDevices(new Class<?>[]{VirtualDisk.class, VirtualEthernetCard.class});
|
||||||
else
|
else
|
||||||
@ -1925,7 +1985,20 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The number of disks changed must be 0 for install as is, as the VM is a clone
|
||||||
|
//int disksChanges = !installAsIs ? disks.length : 0;
|
||||||
int totalChangeDevices = disks.length + nics.length;
|
int totalChangeDevices = disks.length + nics.length;
|
||||||
|
int hackDeviceCount = 0;
|
||||||
|
if (diskInfoBuilder != null) {
|
||||||
|
hackDeviceCount += diskInfoBuilder.getDiskCount();
|
||||||
|
}
|
||||||
|
hackDeviceCount += nicDevices == null ? 0 : nicDevices.length;
|
||||||
|
if (s_logger.isTraceEnabled()) {
|
||||||
|
s_logger.trace(String.format("current count(s) desired: %d/ found:%d. now adding device to device count for vApp config ISO", totalChangeDevices, hackDeviceCount));
|
||||||
|
}
|
||||||
|
if (vmSpec.getOvfProperties() != null) {
|
||||||
|
totalChangeDevices++;
|
||||||
|
}
|
||||||
|
|
||||||
DiskTO volIso = null;
|
DiskTO volIso = null;
|
||||||
if (vmSpec.getType() != VirtualMachine.Type.User) {
|
if (vmSpec.getType() != VirtualMachine.Type.User) {
|
||||||
@ -2309,15 +2382,11 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
configureVideoCard(vmMo, vmSpec, vmConfigSpec);
|
configureVideoCard(vmMo, vmSpec, vmConfigSpec);
|
||||||
|
|
||||||
// Set OVF properties (if available)
|
// Set OVF properties (if available)
|
||||||
Pair<String, List<OVFPropertyTO>> ovfPropsMap = vmSpec.getOvfProperties();
|
List<OVFPropertyTO> ovfProperties = vmSpec.getOvfProperties();
|
||||||
VmConfigInfo templateVappConfig = null;
|
VmConfigInfo templateVappConfig;
|
||||||
List<OVFPropertyTO> ovfProperties = null;
|
if (ovfProperties != null) {
|
||||||
if (ovfPropsMap != null) {
|
VirtualMachineMO templateVMmo = dcMo.findVm(deployAsIsInfo.getTemplatePath());
|
||||||
String vmTemplate = ovfPropsMap.first();
|
templateVappConfig = templateVMmo.getConfigInfo().getVAppConfig();
|
||||||
s_logger.info("Find VM template " + vmTemplate);
|
|
||||||
VirtualMachineMO vmTemplateMO = dcMo.findVm(vmTemplate);
|
|
||||||
templateVappConfig = vmTemplateMO.getConfigInfo().getVAppConfig();
|
|
||||||
ovfProperties = ovfPropsMap.second();
|
|
||||||
// Set OVF properties (if available)
|
// Set OVF properties (if available)
|
||||||
if (CollectionUtils.isNotEmpty(ovfProperties)) {
|
if (CollectionUtils.isNotEmpty(ovfProperties)) {
|
||||||
s_logger.info("Copying OVF properties from template and setting them to the values the user provided");
|
s_logger.info("Copying OVF properties from template and setting them to the values the user provided");
|
||||||
@ -2414,6 +2483,85 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getDatastoreFromSpecDisks(DiskTO[] specDisks) {
|
||||||
|
if (specDisks.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, List<DiskTO>> psDisksMap = Arrays.asList(specDisks).stream()
|
||||||
|
.filter(x -> x.getType() != Volume.Type.ISO && x.getData() != null && x.getData().getDataStore() != null)
|
||||||
|
.collect(Collectors.groupingBy(x -> x.getData().getDataStore().getUuid()));
|
||||||
|
|
||||||
|
String dataStore;
|
||||||
|
if (MapUtils.isEmpty(psDisksMap)) {
|
||||||
|
s_logger.error("Could not find a destination datastore for VM volumes");
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
dataStore = psDisksMap.keySet().iterator().next();
|
||||||
|
if (psDisksMap.keySet().size() > 1) {
|
||||||
|
s_logger.info("Found multiple destination datastores for VM volumes, selecting " + dataStore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dataStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modify the specDisks information to match the cloned VM's disks (from vmMo VM)
|
||||||
|
*/
|
||||||
|
private void mapSpecDisksToClonedDisks(VirtualMachineMO vmMo, String vmInternalCSName, DiskTO[] specDisks) {
|
||||||
|
try {
|
||||||
|
s_logger.debug("Mapping spec disks information to cloned VM disks for VM " + vmInternalCSName);
|
||||||
|
if (vmMo != null && ArrayUtils.isNotEmpty(specDisks)) {
|
||||||
|
List<VirtualDisk> vmDisks = vmMo.getVirtualDisks();
|
||||||
|
List<DiskTO> sortedDisks = Arrays.asList(sortVolumesByDeviceId(specDisks))
|
||||||
|
.stream()
|
||||||
|
.filter(x -> x.getType() == Volume.Type.ROOT)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (sortedDisks.size() != vmDisks.size()) {
|
||||||
|
s_logger.error("Different number of root disks spec vs cloned deploy-as-is VM disks: " + sortedDisks.size() + " - " + vmDisks.size());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < sortedDisks.size(); i++) {
|
||||||
|
DiskTO specDisk = sortedDisks.get(i);
|
||||||
|
VirtualDisk vmDisk = vmDisks.get(i);
|
||||||
|
DataTO dataVolume = specDisk.getData();
|
||||||
|
if (dataVolume instanceof VolumeObjectTO) {
|
||||||
|
VolumeObjectTO volumeObjectTO = (VolumeObjectTO) dataVolume;
|
||||||
|
if (!volumeObjectTO.getSize().equals(vmDisk.getCapacityInBytes())) {
|
||||||
|
s_logger.info("Mapped disk size is not the same as the cloned VM disk size: " +
|
||||||
|
volumeObjectTO.getSize() + " - " + vmDisk.getCapacityInBytes());
|
||||||
|
}
|
||||||
|
VirtualDeviceBackingInfo backingInfo = vmDisk.getBacking();
|
||||||
|
if (backingInfo instanceof VirtualDiskFlatVer2BackingInfo) {
|
||||||
|
VirtualDiskFlatVer2BackingInfo backing = (VirtualDiskFlatVer2BackingInfo) backingInfo;
|
||||||
|
String fileName = backing.getFileName();
|
||||||
|
if (StringUtils.isNotBlank(fileName)) {
|
||||||
|
String[] fileNameParts = fileName.split(" ");
|
||||||
|
String datastoreUuid = fileNameParts[0].replace("[", "").replace("]", "");
|
||||||
|
String relativePath = fileNameParts[1].split("/")[1].replace(".vmdk", "");
|
||||||
|
String vmSpecDatastoreUuid = volumeObjectTO.getDataStore().getUuid().replaceAll("-", "");
|
||||||
|
if (!datastoreUuid.equals(vmSpecDatastoreUuid)) {
|
||||||
|
s_logger.info("Mapped disk datastore UUID is not the same as the cloned VM datastore UUID: " +
|
||||||
|
datastoreUuid + " - " + vmSpecDatastoreUuid);
|
||||||
|
}
|
||||||
|
volumeObjectTO.setPath(relativePath);
|
||||||
|
specDisk.setPath(relativePath);
|
||||||
|
} else {
|
||||||
|
s_logger.error("Empty backing filename for volume " + volumeObjectTO.getName());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s_logger.error("Could not get volume backing info for volume " + volumeObjectTO.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
String msg = "Error mapping deploy-as-is VM disks from cloned VM " + vmInternalCSName;
|
||||||
|
s_logger.error(msg, e);
|
||||||
|
throw new CloudRuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void setBootOptions(VirtualMachineTO vmSpec, String bootMode, VirtualMachineConfigSpec vmConfigSpec) {
|
private void setBootOptions(VirtualMachineTO vmSpec, String bootMode, VirtualMachineConfigSpec vmConfigSpec) {
|
||||||
VirtualMachineBootOptions bootOptions = null;
|
VirtualMachineBootOptions bootOptions = null;
|
||||||
if (StringUtils.isNotBlank(bootMode) && !bootMode.equalsIgnoreCase("bios")) {
|
if (StringUtils.isNotBlank(bootMode) && !bootMode.equalsIgnoreCase("bios")) {
|
||||||
@ -2457,12 +2605,22 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
private Map<String, Pair<String, Boolean>> getOVFMap(List<OVFPropertyTO> props) {
|
private Map<String, Pair<String, Boolean>> getOVFMap(List<OVFPropertyTO> props) {
|
||||||
Map<String, Pair<String, Boolean>> map = new HashMap<>();
|
Map<String, Pair<String, Boolean>> map = new HashMap<>();
|
||||||
for (OVFPropertyTO prop : props) {
|
for (OVFPropertyTO prop : props) {
|
||||||
Pair<String, Boolean> pair = new Pair<>(prop.getValue(), prop.isPassword());
|
String value = getPropertyValue(prop);
|
||||||
|
Pair<String, Boolean> pair = new Pair<>(value, prop.isPassword());
|
||||||
map.put(prop.getKey(), pair);
|
map.put(prop.getKey(), pair);
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getPropertyValue(OVFPropertyTO prop) {
|
||||||
|
String type = prop.getType();
|
||||||
|
String value = prop.getValue();
|
||||||
|
if ("boolean".equalsIgnoreCase(type)) {
|
||||||
|
value = Boolean.parseBoolean(value) ? "True" : "False";
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the properties section from existing vApp configuration and values set on ovfProperties
|
* Set the properties section from existing vApp configuration and values set on ovfProperties
|
||||||
*/
|
*/
|
||||||
@ -2843,7 +3001,10 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||||||
private static void configCustomExtraOption(List<OptionValue> extraOptions, VirtualMachineTO vmSpec) {
|
private static void configCustomExtraOption(List<OptionValue> extraOptions, VirtualMachineTO vmSpec) {
|
||||||
// we no longer to validation anymore
|
// we no longer to validation anymore
|
||||||
for (Map.Entry<String, String> entry : vmSpec.getDetails().entrySet()) {
|
for (Map.Entry<String, String> entry : vmSpec.getDetails().entrySet()) {
|
||||||
if (entry.getKey().equalsIgnoreCase(VmDetailConstants.BOOT_MODE)) {
|
if (entry.getKey().equalsIgnoreCase(VmDetailConstants.BOOT_MODE) ||
|
||||||
|
entry.getKey().startsWith(ImageStore.REQUIRED_NETWORK_PREFIX) ||
|
||||||
|
entry.getKey().startsWith(ImageStore.ACS_PROPERTY_PREFIX) ||
|
||||||
|
entry.getKey().startsWith(ImageStore.DISK_DEFINITION_PREFIX)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
OptionValue newVal = new OptionValue();
|
OptionValue newVal = new OptionValue();
|
||||||
|
|||||||
@ -795,7 +795,10 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
|||||||
DatastoreMO dsMo = new DatastoreMO(context, morDatastore);
|
DatastoreMO dsMo = new DatastoreMO(context, morDatastore);
|
||||||
|
|
||||||
String vmdkName = volume.getName();
|
String vmdkName = volume.getName();
|
||||||
String vmdkFileBaseName;
|
String vmdkFileBaseName = null;
|
||||||
|
if (template.isDeployAsIs()) {
|
||||||
|
s_logger.info("Volume from deploy-as-is template, no need to create the volume at this point, VM will be cloned");
|
||||||
|
} else {
|
||||||
if (srcStore == null) {
|
if (srcStore == null) {
|
||||||
// create a root volume for blank VM (created from ISO)
|
// create a root volume for blank VM (created from ISO)
|
||||||
String dummyVmName = hostService.getWorkerName(context, cmd, 0);
|
String dummyVmName = hostService.getWorkerName(context, cmd, 0);
|
||||||
@ -877,13 +880,15 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
|||||||
VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmNameInVcenter, dsMo, vmdkFileBaseName, searchExcludedFolders);
|
VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmNameInVcenter, dsMo, vmdkFileBaseName, searchExcludedFolders);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VolumeObjectTO newVol = new VolumeObjectTO();
|
VolumeObjectTO newVol = new VolumeObjectTO();
|
||||||
newVol.setPath(vmdkFileBaseName);
|
newVol.setPath(vmdkFileBaseName);
|
||||||
if (template.getSize() != null){
|
if (template.isDeployAsIs()) {
|
||||||
|
newVol.setSize(volume.getSize());
|
||||||
|
} else if (template.getSize() != null) {
|
||||||
newVol.setSize(template.getSize());
|
newVol.setSize(template.getSize());
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
newVol.setSize(volume.getSize());
|
newVol.setSize(volume.getSize());
|
||||||
}
|
}
|
||||||
return new CopyCmdAnswer(newVol);
|
return new CopyCmdAnswer(newVol);
|
||||||
@ -899,6 +904,18 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createLinkedOrFullClone(TemplateObjectTO template, VolumeObjectTO volume, DatacenterMO dcMo, VirtualMachineMO vmMo, ManagedObjectReference morDatastore,
|
||||||
|
DatastoreMO dsMo, String cloneName, ManagedObjectReference morPool) throws Exception {
|
||||||
|
if (template.getSize() != null) {
|
||||||
|
_fullCloneFlag = volume.getSize() > template.getSize() || _fullCloneFlag;
|
||||||
|
}
|
||||||
|
if (!_fullCloneFlag) {
|
||||||
|
createVMLinkedClone(vmMo, dcMo, cloneName, morDatastore, morPool);
|
||||||
|
} else {
|
||||||
|
createVMFullClone(vmMo, dcMo, dsMo, cloneName, morDatastore, morPool);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Pair<String, String> copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, String srcVolumePath, DatastoreMO dsMo, String secStorageUrl,
|
private Pair<String, String> copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, String srcVolumePath, DatastoreMO dsMo, String secStorageUrl,
|
||||||
long wait, String nfsVersion) throws Exception {
|
long wait, String nfsVersion) throws Exception {
|
||||||
String volumeFolder;
|
String volumeFolder;
|
||||||
@ -3478,7 +3495,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
|||||||
|
|
||||||
VirtualMachineMO clonedVm = null;
|
VirtualMachineMO clonedVm = null;
|
||||||
try {
|
try {
|
||||||
hyperHost.importVmFromOVF(srcOVFFileName, newVolumeName, primaryDsMo, "thin");
|
hyperHost.importVmFromOVF(srcOVFFileName, newVolumeName, primaryDsMo, "thin", null);
|
||||||
clonedVm = hyperHost.findVmOnHyperHost(newVolumeName);
|
clonedVm = hyperHost.findVmOnHyperHost(newVolumeName);
|
||||||
if (clonedVm == null) {
|
if (clonedVm == null) {
|
||||||
throw new Exception("Unable to create container VM for volume creation");
|
throw new Exception("Unable to create container VM for volume creation");
|
||||||
@ -3640,4 +3657,40 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
|||||||
public Answer copyVolumeFromPrimaryToPrimary(CopyCommand cmd) {
|
public Answer copyVolumeFromPrimaryToPrimary(CopyCommand cmd) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the cloned VM from the template
|
||||||
|
*/
|
||||||
|
public VirtualMachineMO cloneVMFromTemplate(String templateName, String cloneName, String templatePrimaryStoreUuid) {
|
||||||
|
try {
|
||||||
|
VmwareContext context = hostService.getServiceContext(null);
|
||||||
|
VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, null);
|
||||||
|
DatacenterMO dcMo = new DatacenterMO(context, hyperHost.getHyperHostDatacenter());
|
||||||
|
VirtualMachineMO templateMo = dcMo.findVm(templateName);
|
||||||
|
if (templateMo == null) {
|
||||||
|
throw new CloudRuntimeException(String.format("Unable to find template %s in vSphere", templateName));
|
||||||
|
}
|
||||||
|
ManagedObjectReference morDatastore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, templatePrimaryStoreUuid);
|
||||||
|
DatastoreMO dsMo = new DatastoreMO(context, morDatastore);
|
||||||
|
ManagedObjectReference morPool = hyperHost.getHyperHostOwnerResourcePool();
|
||||||
|
if (morDatastore == null) {
|
||||||
|
throw new CloudRuntimeException("Unable to find datastore in vSphere");
|
||||||
|
}
|
||||||
|
s_logger.info("Cloning VM " + cloneName + " from template " + templatePrimaryStoreUuid);
|
||||||
|
if (!_fullCloneFlag) {
|
||||||
|
createVMLinkedClone(templateMo, dcMo, cloneName, morDatastore, morPool);
|
||||||
|
} else {
|
||||||
|
createVMFullClone(templateMo, dcMo, dsMo, cloneName, morDatastore, morPool);
|
||||||
|
}
|
||||||
|
VirtualMachineMO vm = dcMo.findVm(cloneName);
|
||||||
|
if (vm == null) {
|
||||||
|
throw new CloudRuntimeException("Unable to get the cloned VM " + cloneName);
|
||||||
|
}
|
||||||
|
return vm;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
String msg = "Error cloning VM from template in primary storage: %s" + e.getMessage();
|
||||||
|
s_logger.error(msg, e);
|
||||||
|
throw new CloudRuntimeException(msg, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -955,7 +955,7 @@ public class DateraPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
} else if (dataType == DataObjectType.TEMPLATE) {
|
} else if (dataType == DataObjectType.TEMPLATE) {
|
||||||
s_logger.debug("Clone volume from a template");
|
s_logger.debug("Clone volume from a template");
|
||||||
|
|
||||||
VMTemplateStoragePoolVO templatePoolRef = tmpltPoolDao.findByPoolTemplate(storagePoolId, dataObjectId);
|
VMTemplateStoragePoolVO templatePoolRef = tmpltPoolDao.findByPoolTemplate(storagePoolId, dataObjectId, null);
|
||||||
|
|
||||||
if (templatePoolRef != null) {
|
if (templatePoolRef != null) {
|
||||||
baseAppInstanceName = templatePoolRef.getLocalDownloadPath();
|
baseAppInstanceName = templatePoolRef.getLocalDownloadPath();
|
||||||
@ -1114,7 +1114,7 @@ public class DateraPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
iqn = appInstance.getIqn();
|
iqn = appInstance.getIqn();
|
||||||
|
|
||||||
VMTemplateStoragePoolVO templatePoolRef = tmpltPoolDao.findByPoolTemplate(storagePoolId,
|
VMTemplateStoragePoolVO templatePoolRef = tmpltPoolDao.findByPoolTemplate(storagePoolId,
|
||||||
templateInfo.getId());
|
templateInfo.getId(), null);
|
||||||
|
|
||||||
templatePoolRef.setInstallPath(DateraUtil.generateIqnPath(iqn));
|
templatePoolRef.setInstallPath(DateraUtil.generateIqnPath(iqn));
|
||||||
templatePoolRef.setLocalDownloadPath(appInstance.getName());
|
templatePoolRef.setLocalDownloadPath(appInstance.getName());
|
||||||
@ -1505,7 +1505,7 @@ public class DateraPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
DateraUtil.deleteAppInstance(conn, appInstanceName);
|
DateraUtil.deleteAppInstance(conn, appInstanceName);
|
||||||
|
|
||||||
VMTemplateStoragePoolVO templatePoolRef = tmpltPoolDao.findByPoolTemplate(storagePoolId,
|
VMTemplateStoragePoolVO templatePoolRef = tmpltPoolDao.findByPoolTemplate(storagePoolId,
|
||||||
templateInfo.getId());
|
templateInfo.getId(), null);
|
||||||
|
|
||||||
tmpltPoolDao.remove(templatePoolRef.getId());
|
tmpltPoolDao.remove(templatePoolRef.getId());
|
||||||
|
|
||||||
|
|||||||
@ -709,7 +709,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
sfVolumeId = Long.parseLong(snapshotDetails.getValue());
|
sfVolumeId = Long.parseLong(snapshotDetails.getValue());
|
||||||
} else if (dataObjectType == DataObjectType.TEMPLATE) {
|
} else if (dataObjectType == DataObjectType.TEMPLATE) {
|
||||||
// get the cached template on this storage
|
// get the cached template on this storage
|
||||||
VMTemplateStoragePoolVO templatePoolRef = vmTemplatePoolDao.findByPoolTemplate(storagePoolId, dataObjectId);
|
VMTemplateStoragePoolVO templatePoolRef = vmTemplatePoolDao.findByPoolTemplate(storagePoolId, dataObjectId, null);
|
||||||
|
|
||||||
if (templatePoolRef != null) {
|
if (templatePoolRef != null) {
|
||||||
sfVolumeId = Long.parseLong(templatePoolRef.getLocalDownloadPath());
|
sfVolumeId = Long.parseLong(templatePoolRef.getLocalDownloadPath());
|
||||||
@ -1135,7 +1135,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
|
|
||||||
String iqn = sfVolume.getIqn();
|
String iqn = sfVolume.getIqn();
|
||||||
|
|
||||||
VMTemplateStoragePoolVO templatePoolRef = vmTemplatePoolDao.findByPoolTemplate(storagePoolId, templateInfo.getId());
|
VMTemplateStoragePoolVO templatePoolRef = vmTemplatePoolDao.findByPoolTemplate(storagePoolId, templateInfo.getId(), null);
|
||||||
|
|
||||||
templatePoolRef.setInstallPath(iqn);
|
templatePoolRef.setInstallPath(iqn);
|
||||||
templatePoolRef.setLocalDownloadPath(Long.toString(sfVolume.getId()));
|
templatePoolRef.setLocalDownloadPath(Long.toString(sfVolume.getId()));
|
||||||
|
|||||||
@ -2004,16 +2004,16 @@ public class ApiDBUtils {
|
|||||||
return s_templateJoinDao.newUpdateResponse(vr);
|
return s_templateJoinDao.newUpdateResponse(vr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TemplateResponse newTemplateResponse(ResponseView view, TemplateJoinVO vr) {
|
public static TemplateResponse newTemplateResponse(EnumSet<DomainDetails> detailsView, ResponseView view, TemplateJoinVO vr) {
|
||||||
return s_templateJoinDao.newTemplateResponse(view, vr);
|
return s_templateJoinDao.newTemplateResponse(detailsView, view, vr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TemplateResponse newIsoResponse(TemplateJoinVO vr) {
|
public static TemplateResponse newIsoResponse(TemplateJoinVO vr) {
|
||||||
return s_templateJoinDao.newIsoResponse(vr);
|
return s_templateJoinDao.newIsoResponse(vr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TemplateResponse fillTemplateDetails(ResponseView view, TemplateResponse vrData, TemplateJoinVO vr) {
|
public static TemplateResponse fillTemplateDetails(EnumSet<DomainDetails> detailsView, ResponseView view, TemplateResponse vrData, TemplateJoinVO vr) {
|
||||||
return s_templateJoinDao.setTemplateResponse(view, vrData, vr);
|
return s_templateJoinDao.setTemplateResponse(detailsView, view, vrData, vr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<TemplateJoinVO> newTemplateView(VirtualMachineTemplate vr) {
|
public static List<TemplateJoinVO> newTemplateView(VirtualMachineTemplate vr) {
|
||||||
|
|||||||
@ -1564,7 +1564,7 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||||||
tvo = ApiDBUtils.newTemplateView(result, zoneId, readyOnly);
|
tvo = ApiDBUtils.newTemplateView(result, zoneId, readyOnly);
|
||||||
|
|
||||||
}
|
}
|
||||||
return ViewResponseHelper.createTemplateResponse(view, tvo.toArray(new TemplateJoinVO[tvo.size()]));
|
return ViewResponseHelper.createTemplateResponse(EnumSet.of(DomainDetails.all), view, tvo.toArray(new TemplateJoinVO[tvo.size()]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1581,7 +1581,7 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||||||
tvo.addAll(ApiDBUtils.newTemplateView(result, zoneId, readyOnly));
|
tvo.addAll(ApiDBUtils.newTemplateView(result, zoneId, readyOnly));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ViewResponseHelper.createTemplateResponse(view, tvo.toArray(new TemplateJoinVO[tvo.size()]));
|
return ViewResponseHelper.createTemplateResponse(EnumSet.of(DomainDetails.all), view, tvo.toArray(new TemplateJoinVO[tvo.size()]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -31,6 +31,7 @@ import java.util.stream.Stream;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import com.cloud.storage.dao.VMTemplateDetailsDao;
|
||||||
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
|
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
|
||||||
import org.apache.cloudstack.affinity.AffinityGroupDomainMapVO;
|
import org.apache.cloudstack.affinity.AffinityGroupDomainMapVO;
|
||||||
import org.apache.cloudstack.affinity.AffinityGroupResponse;
|
import org.apache.cloudstack.affinity.AffinityGroupResponse;
|
||||||
@ -71,7 +72,6 @@ import org.apache.cloudstack.api.command.user.project.ListProjectsCmd;
|
|||||||
import org.apache.cloudstack.api.command.user.resource.ListDetailOptionsCmd;
|
import org.apache.cloudstack.api.command.user.resource.ListDetailOptionsCmd;
|
||||||
import org.apache.cloudstack.api.command.user.securitygroup.ListSecurityGroupsCmd;
|
import org.apache.cloudstack.api.command.user.securitygroup.ListSecurityGroupsCmd;
|
||||||
import org.apache.cloudstack.api.command.user.tag.ListTagsCmd;
|
import org.apache.cloudstack.api.command.user.tag.ListTagsCmd;
|
||||||
import org.apache.cloudstack.api.command.user.template.ListTemplateOVFProperties;
|
|
||||||
import org.apache.cloudstack.api.command.user.template.ListTemplatesCmd;
|
import org.apache.cloudstack.api.command.user.template.ListTemplatesCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vm.ListVMsCmd;
|
import org.apache.cloudstack.api.command.user.vm.ListVMsCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd;
|
import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd;
|
||||||
@ -101,7 +101,6 @@ import org.apache.cloudstack.api.response.SecurityGroupResponse;
|
|||||||
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
|
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
|
||||||
import org.apache.cloudstack.api.response.StoragePoolResponse;
|
import org.apache.cloudstack.api.response.StoragePoolResponse;
|
||||||
import org.apache.cloudstack.api.response.StorageTagResponse;
|
import org.apache.cloudstack.api.response.StorageTagResponse;
|
||||||
import org.apache.cloudstack.api.response.TemplateOVFPropertyResponse;
|
|
||||||
import org.apache.cloudstack.api.response.TemplateResponse;
|
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||||
import org.apache.cloudstack.api.response.UserResponse;
|
import org.apache.cloudstack.api.response.UserResponse;
|
||||||
import org.apache.cloudstack.api.response.UserVmResponse;
|
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||||
@ -125,7 +124,6 @@ import org.apache.commons.collections.CollectionUtils;
|
|||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.cloud.agent.api.storage.OVFProperty;
|
|
||||||
import com.cloud.api.query.dao.AccountJoinDao;
|
import com.cloud.api.query.dao.AccountJoinDao;
|
||||||
import com.cloud.api.query.dao.AffinityGroupJoinDao;
|
import com.cloud.api.query.dao.AffinityGroupJoinDao;
|
||||||
import com.cloud.api.query.dao.AsyncJobJoinDao;
|
import com.cloud.api.query.dao.AsyncJobJoinDao;
|
||||||
@ -214,11 +212,9 @@ import com.cloud.storage.Storage;
|
|||||||
import com.cloud.storage.Storage.ImageFormat;
|
import com.cloud.storage.Storage.ImageFormat;
|
||||||
import com.cloud.storage.Storage.TemplateType;
|
import com.cloud.storage.Storage.TemplateType;
|
||||||
import com.cloud.storage.StoragePoolTagVO;
|
import com.cloud.storage.StoragePoolTagVO;
|
||||||
import com.cloud.storage.TemplateOVFPropertyVO;
|
|
||||||
import com.cloud.storage.VMTemplateVO;
|
import com.cloud.storage.VMTemplateVO;
|
||||||
import com.cloud.storage.Volume;
|
import com.cloud.storage.Volume;
|
||||||
import com.cloud.storage.dao.StoragePoolTagsDao;
|
import com.cloud.storage.dao.StoragePoolTagsDao;
|
||||||
import com.cloud.storage.dao.TemplateOVFPropertiesDao;
|
|
||||||
import com.cloud.storage.dao.VMTemplateDao;
|
import com.cloud.storage.dao.VMTemplateDao;
|
||||||
import com.cloud.tags.ResourceTagVO;
|
import com.cloud.tags.ResourceTagVO;
|
||||||
import com.cloud.tags.dao.ResourceTagDao;
|
import com.cloud.tags.dao.ResourceTagDao;
|
||||||
@ -405,7 +401,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||||||
ManagementServerHostDao managementServerHostDao;
|
ManagementServerHostDao managementServerHostDao;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
TemplateOVFPropertiesDao templateOVFPropertiesDao;
|
VMTemplateDetailsDao vmTemplateDetailsDao;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public VpcVirtualNetworkApplianceService routerService;
|
public VpcVirtualNetworkApplianceService routerService;
|
||||||
@ -2919,6 +2915,9 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||||||
ServiceOfferingVO currentVmOffering = null;
|
ServiceOfferingVO currentVmOffering = null;
|
||||||
Boolean isRecursive = cmd.isRecursive();
|
Boolean isRecursive = cmd.isRecursive();
|
||||||
Long zoneId = cmd.getZoneId();
|
Long zoneId = cmd.getZoneId();
|
||||||
|
Integer cpuNumber = cmd.getCpuNumber();
|
||||||
|
Integer memory = cmd.getMemory();
|
||||||
|
Integer cpuSpeed = cmd.getCpuSpeed();
|
||||||
|
|
||||||
SearchCriteria<ServiceOfferingJoinVO> sc = _srvOfferingJoinDao.createSearchCriteria();
|
SearchCriteria<ServiceOfferingJoinVO> sc = _srvOfferingJoinDao.createSearchCriteria();
|
||||||
if (!_accountMgr.isRootAdmin(caller.getId()) && isSystem) {
|
if (!_accountMgr.isRootAdmin(caller.getId()) && isSystem) {
|
||||||
@ -2970,35 +2969,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||||||
if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL) {
|
if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL) {
|
||||||
throw new InvalidParameterValueException("Only ROOT admins and Domain admins can list service offerings with isrecursive=true");
|
throw new InvalidParameterValueException("Only ROOT admins and Domain admins can list service offerings with isrecursive=true");
|
||||||
}
|
}
|
||||||
}/* else { // domain + all ancestors
|
|
||||||
// find all domain Id up to root domain for this account
|
|
||||||
List<Long> domainIds = new ArrayList<Long>();
|
|
||||||
DomainVO domainRecord;
|
|
||||||
if (vmId != null) {
|
|
||||||
UserVmVO vmInstance = _userVmDao.findById(vmId);
|
|
||||||
domainRecord = _domainDao.findById(vmInstance.getDomainId());
|
|
||||||
if (domainRecord == null) {
|
|
||||||
s_logger.error("Could not find the domainId for vmId:" + vmId);
|
|
||||||
throw new CloudAuthenticationException("Could not find the domainId for vmId:" + vmId);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
domainRecord = _domainDao.findById(caller.getDomainId());
|
|
||||||
if (domainRecord == null) {
|
|
||||||
s_logger.error("Could not find the domainId for account:" + caller.getAccountName());
|
|
||||||
throw new CloudAuthenticationException("Could not find the domainId for account:" + caller.getAccountName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
domainIds.add(domainRecord.getId());
|
|
||||||
while (domainRecord.getParent() != null) {
|
|
||||||
domainRecord = _domainDao.findById(domainRecord.getParent());
|
|
||||||
domainIds.add(domainRecord.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchCriteria<ServiceOfferingJoinVO> spc = _srvOfferingJoinDao.createSearchCriteria();
|
|
||||||
spc.addOr("domainId", SearchCriteria.Op.IN, domainIds.toArray());
|
|
||||||
spc.addOr("domainId", SearchCriteria.Op.NULL); // include public offering as well
|
|
||||||
sc.addAnd("domainId", SearchCriteria.Op.SC, spc);
|
|
||||||
}*/
|
|
||||||
} else {
|
} else {
|
||||||
// for root users
|
// for root users
|
||||||
if (caller.getDomainId() != 1 && isSystem) { // NON ROOT admin
|
if (caller.getDomainId() != 1 && isSystem) { // NON ROOT admin
|
||||||
@ -3045,6 +3016,37 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||||||
sc.addAnd("zoneId", SearchCriteria.Op.SC, zoneSC);
|
sc.addAnd("zoneId", SearchCriteria.Op.SC, zoneSC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cpuNumber != null) {
|
||||||
|
SearchCriteria<ServiceOfferingJoinVO> cpuConstraintSearchCriteria = _srvOfferingJoinDao.createSearchCriteria();
|
||||||
|
cpuConstraintSearchCriteria.addAnd("minCpu", Op.LTEQ, cpuNumber);
|
||||||
|
cpuConstraintSearchCriteria.addAnd("maxCpu", Op.GTEQ, cpuNumber);
|
||||||
|
|
||||||
|
SearchCriteria<ServiceOfferingJoinVO> cpuSearchCriteria = _srvOfferingJoinDao.createSearchCriteria();
|
||||||
|
cpuSearchCriteria.addOr("minCpu", Op.NULL);
|
||||||
|
cpuSearchCriteria.addOr("constraints", Op.SC, cpuConstraintSearchCriteria);
|
||||||
|
|
||||||
|
sc.addAnd("cpuConstraints", SearchCriteria.Op.SC, cpuSearchCriteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memory != null) {
|
||||||
|
SearchCriteria<ServiceOfferingJoinVO> memoryConstraintSearchCriteria = _srvOfferingJoinDao.createSearchCriteria();
|
||||||
|
memoryConstraintSearchCriteria.addAnd("minMemory", Op.LTEQ, memory);
|
||||||
|
memoryConstraintSearchCriteria.addAnd("maxMemory", Op.GTEQ, memory);
|
||||||
|
|
||||||
|
SearchCriteria<ServiceOfferingJoinVO> memSearchCriteria = _srvOfferingJoinDao.createSearchCriteria();
|
||||||
|
memSearchCriteria.addOr("minMemory", Op.NULL);
|
||||||
|
memSearchCriteria.addOr("memconstraints", Op.SC, memoryConstraintSearchCriteria);
|
||||||
|
|
||||||
|
sc.addAnd("memoryConstraints", SearchCriteria.Op.SC, memSearchCriteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpuSpeed != null) {
|
||||||
|
SearchCriteria<ServiceOfferingJoinVO> cpuSpeedSearchCriteria = _srvOfferingJoinDao.createSearchCriteria();
|
||||||
|
cpuSpeedSearchCriteria.addOr("speed", Op.NULL);
|
||||||
|
cpuSpeedSearchCriteria.addOr("speed", Op.EQ, cpuSpeed);
|
||||||
|
sc.addAnd("cpuspeedconstraints", SearchCriteria.Op.SC, cpuSpeedSearchCriteria);
|
||||||
|
}
|
||||||
|
|
||||||
Pair<List<ServiceOfferingJoinVO>, Integer> result = _srvOfferingJoinDao.searchAndCount(sc, searchFilter);
|
Pair<List<ServiceOfferingJoinVO>, Integer> result = _srvOfferingJoinDao.searchAndCount(sc, searchFilter);
|
||||||
|
|
||||||
//Couldn't figure out a smart way to filter offerings based on tags in sql so doing it in Java.
|
//Couldn't figure out a smart way to filter offerings based on tags in sql so doing it in Java.
|
||||||
@ -3325,7 +3327,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||||||
respView = ResponseView.Full;
|
respView = ResponseView.Full;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<TemplateResponse> templateResponses = ViewResponseHelper.createTemplateResponse(respView, result.first().toArray(new TemplateJoinVO[result.first().size()]));
|
List<TemplateResponse> templateResponses = ViewResponseHelper.createTemplateResponse(cmd.getDetails(), respView, result.first().toArray(new TemplateJoinVO[result.first().size()]));
|
||||||
response.setResponses(templateResponses, result.second());
|
response.setResponses(templateResponses, result.second());
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
@ -4095,29 +4097,6 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||||||
return mgmtResponse;
|
return mgmtResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ListResponse<TemplateOVFPropertyResponse> listTemplateOVFProperties(ListTemplateOVFProperties cmd) {
|
|
||||||
ListResponse<TemplateOVFPropertyResponse> response = new ListResponse<>();
|
|
||||||
List<TemplateOVFPropertyResponse> result = new ArrayList<>();
|
|
||||||
Long templateId = cmd.getTemplateId();
|
|
||||||
List<TemplateOVFPropertyVO> ovfProperties = templateOVFPropertiesDao.listByTemplateId(templateId);
|
|
||||||
for (OVFProperty property : ovfProperties) {
|
|
||||||
TemplateOVFPropertyResponse propertyResponse = new TemplateOVFPropertyResponse();
|
|
||||||
propertyResponse.setKey(property.getKey());
|
|
||||||
propertyResponse.setType(property.getType());
|
|
||||||
propertyResponse.setValue(property.getValue());
|
|
||||||
propertyResponse.setQualifiers(property.getQualifiers());
|
|
||||||
propertyResponse.setUserConfigurable(property.isUserConfigurable());
|
|
||||||
propertyResponse.setLabel(property.getLabel());
|
|
||||||
propertyResponse.setDescription(property.getDescription());
|
|
||||||
propertyResponse.setPassword(property.isPassword());
|
|
||||||
propertyResponse.setObjectName("ovfproperty");
|
|
||||||
result.add(propertyResponse);
|
|
||||||
}
|
|
||||||
response.setResponses(result);
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<RouterHealthCheckResultResponse> listRouterHealthChecks(GetRouterHealthCheckResultsCmd cmd) {
|
public List<RouterHealthCheckResultResponse> listRouterHealthChecks(GetRouterHealthCheckResultsCmd cmd) {
|
||||||
s_logger.info("Executing health check command " + cmd);
|
s_logger.info("Executing health check command " + cmd);
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
import org.apache.cloudstack.affinity.AffinityGroupResponse;
|
import org.apache.cloudstack.affinity.AffinityGroupResponse;
|
||||||
import org.apache.cloudstack.api.ApiConstants.DomainDetails;
|
import org.apache.cloudstack.api.ApiConstants.DomainDetails;
|
||||||
import org.apache.cloudstack.api.ApiConstants.HostDetails;
|
import org.apache.cloudstack.api.ApiConstants.HostDetails;
|
||||||
@ -583,17 +584,17 @@ public class ViewResponseHelper {
|
|||||||
return respList;
|
return respList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<TemplateResponse> createTemplateResponse(ResponseView view, TemplateJoinVO... templates) {
|
public static List<TemplateResponse> createTemplateResponse(EnumSet<ApiConstants.DomainDetails> detailsView, ResponseView view, TemplateJoinVO... templates) {
|
||||||
LinkedHashMap<String, TemplateResponse> vrDataList = new LinkedHashMap<String, TemplateResponse>();
|
LinkedHashMap<String, TemplateResponse> vrDataList = new LinkedHashMap<String, TemplateResponse>();
|
||||||
for (TemplateJoinVO vr : templates) {
|
for (TemplateJoinVO vr : templates) {
|
||||||
TemplateResponse vrData = vrDataList.get(vr.getTempZonePair());
|
TemplateResponse vrData = vrDataList.get(vr.getTempZonePair());
|
||||||
if (vrData == null) {
|
if (vrData == null) {
|
||||||
// first time encountering this volume
|
// first time encountering this volume
|
||||||
vrData = ApiDBUtils.newTemplateResponse(view, vr);
|
vrData = ApiDBUtils.newTemplateResponse(detailsView, view, vr);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
// update tags
|
// update tags
|
||||||
vrData = ApiDBUtils.fillTemplateDetails(view, vrData, vr);
|
vrData = ApiDBUtils.fillTemplateDetails(detailsView, view, vrData, vr);
|
||||||
}
|
}
|
||||||
vrDataList.put(vr.getTempZonePair(), vrData);
|
vrDataList.put(vr.getTempZonePair(), vrData);
|
||||||
}
|
}
|
||||||
@ -609,7 +610,7 @@ public class ViewResponseHelper {
|
|||||||
vrData = ApiDBUtils.newTemplateUpdateResponse(vr);
|
vrData = ApiDBUtils.newTemplateUpdateResponse(vr);
|
||||||
} else {
|
} else {
|
||||||
// update tags
|
// update tags
|
||||||
vrData = ApiDBUtils.fillTemplateDetails(view, vrData, vr);
|
vrData = ApiDBUtils.fillTemplateDetails(EnumSet.of(DomainDetails.all), view, vrData, vr);
|
||||||
}
|
}
|
||||||
vrDataList.put(vr.getId(), vrData);
|
vrDataList.put(vr.getId(), vrData);
|
||||||
}
|
}
|
||||||
@ -625,7 +626,7 @@ public class ViewResponseHelper {
|
|||||||
vrData = ApiDBUtils.newIsoResponse(vr);
|
vrData = ApiDBUtils.newIsoResponse(vr);
|
||||||
} else {
|
} else {
|
||||||
// update tags
|
// update tags
|
||||||
vrData = ApiDBUtils.fillTemplateDetails(view, vrData, vr);
|
vrData = ApiDBUtils.fillTemplateDetails(EnumSet.of(DomainDetails.all), view, vrData, vr);
|
||||||
}
|
}
|
||||||
vrDataList.put(vr.getTempZonePair(), vrData);
|
vrDataList.put(vr.getTempZonePair(), vrData);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,8 +16,10 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.api.query.dao;
|
package com.cloud.api.query.dao;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
||||||
import org.apache.cloudstack.api.response.TemplateResponse;
|
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||||
|
|
||||||
@ -30,13 +32,13 @@ import com.cloud.utils.db.SearchCriteria;
|
|||||||
|
|
||||||
public interface TemplateJoinDao extends GenericDao<TemplateJoinVO, Long> {
|
public interface TemplateJoinDao extends GenericDao<TemplateJoinVO, Long> {
|
||||||
|
|
||||||
TemplateResponse newTemplateResponse(ResponseView view, TemplateJoinVO tmpl);
|
TemplateResponse newTemplateResponse(EnumSet<ApiConstants.DomainDetails> detailsView, ResponseView view, TemplateJoinVO tmpl);
|
||||||
|
|
||||||
TemplateResponse newIsoResponse(TemplateJoinVO tmpl);
|
TemplateResponse newIsoResponse(TemplateJoinVO tmpl);
|
||||||
|
|
||||||
TemplateResponse newUpdateResponse(TemplateJoinVO tmpl);
|
TemplateResponse newUpdateResponse(TemplateJoinVO tmpl);
|
||||||
|
|
||||||
TemplateResponse setTemplateResponse(ResponseView view, TemplateResponse tmplData, TemplateJoinVO tmpl);
|
TemplateResponse setTemplateResponse(EnumSet<ApiConstants.DomainDetails> detailsView, ResponseView view, TemplateResponse tmplData, TemplateJoinVO tmpl);
|
||||||
|
|
||||||
List<TemplateJoinVO> newTemplateView(VirtualMachineTemplate tmpl);
|
List<TemplateJoinVO> newTemplateView(VirtualMachineTemplate tmpl);
|
||||||
|
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
package com.cloud.api.query.dao;
|
package com.cloud.api.query.dao;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -25,6 +26,11 @@ import java.util.Set;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
import org.apache.cloudstack.utils.security.DigestHelper;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
||||||
import org.apache.cloudstack.api.response.ChildTemplateResponse;
|
import org.apache.cloudstack.api.response.ChildTemplateResponse;
|
||||||
import org.apache.cloudstack.api.response.TemplateResponse;
|
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||||
@ -147,7 +153,7 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TemplateResponse newTemplateResponse(ResponseView view, TemplateJoinVO template) {
|
public TemplateResponse newTemplateResponse(EnumSet<ApiConstants.DomainDetails> detailsView, ResponseView view, TemplateJoinVO template) {
|
||||||
List<TemplateDataStoreVO> templatesInStore = _templateStoreDao.listByTemplateNotBypassed(template.getId());
|
List<TemplateDataStoreVO> templatesInStore = _templateStoreDao.listByTemplateNotBypassed(template.getId());
|
||||||
List<Map<String, String>> downloadProgressDetails = new ArrayList();
|
List<Map<String, String>> downloadProgressDetails = new ArrayList();
|
||||||
HashMap<String, String> downloadDetailInImageStores = null;
|
HashMap<String, String> downloadDetailInImageStores = null;
|
||||||
@ -158,6 +164,7 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
|
|||||||
downloadDetailInImageStores.put("downloadState", (templateInStore.getDownloadState() != null ? templateInStore.getDownloadState().toString() : ""));
|
downloadDetailInImageStores.put("downloadState", (templateInStore.getDownloadState() != null ? templateInStore.getDownloadState().toString() : ""));
|
||||||
downloadProgressDetails.add(downloadDetailInImageStores);
|
downloadProgressDetails.add(downloadDetailInImageStores);
|
||||||
}
|
}
|
||||||
|
|
||||||
TemplateResponse templateResponse = new TemplateResponse();
|
TemplateResponse templateResponse = new TemplateResponse();
|
||||||
templateResponse.setDownloadProgress(downloadProgressDetails);
|
templateResponse.setDownloadProgress(downloadProgressDetails);
|
||||||
templateResponse.setId(template.getUuid());
|
templateResponse.setId(template.getUuid());
|
||||||
@ -230,8 +237,10 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set details map
|
// set details map
|
||||||
|
if (detailsView.contains(ApiConstants.DomainDetails.all)) {
|
||||||
Map<String, String> details = _templateDetailsDao.listDetailsKeyPairs(template.getId());
|
Map<String, String> details = _templateDetailsDao.listDetailsKeyPairs(template.getId());
|
||||||
templateResponse.setDetails(details);
|
templateResponse.setDetails(details);
|
||||||
|
}
|
||||||
|
|
||||||
// update tag information
|
// update tag information
|
||||||
long tag_id = template.getTagId();
|
long tag_id = template.getTagId();
|
||||||
@ -240,6 +249,7 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
|
|||||||
}
|
}
|
||||||
|
|
||||||
templateResponse.setDirectDownload(template.isDirectDownload());
|
templateResponse.setDirectDownload(template.isDirectDownload());
|
||||||
|
templateResponse.setDeployAsIs(template.isDeployAsIs());
|
||||||
templateResponse.setRequiresHvm(template.isRequiresHvm());
|
templateResponse.setRequiresHvm(template.isRequiresHvm());
|
||||||
|
|
||||||
//set template children disks
|
//set template children disks
|
||||||
@ -307,16 +317,13 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TemplateResponse setTemplateResponse(ResponseView view, TemplateResponse templateResponse, TemplateJoinVO template) {
|
public TemplateResponse setTemplateResponse(EnumSet<ApiConstants.DomainDetails> detailsView, ResponseView view, TemplateResponse templateResponse, TemplateJoinVO template) {
|
||||||
|
if (detailsView.contains(ApiConstants.DomainDetails.all)) {
|
||||||
// update details map
|
// update details map
|
||||||
if (template.getDetailName() != null) {
|
String key = template.getDetailName();
|
||||||
Map<String, String> details = templateResponse.getDetails();
|
if (key != null) {
|
||||||
if (details == null) {
|
templateResponse.addDetail(key, template.getDetailValue());
|
||||||
details = new HashMap<>();
|
|
||||||
}
|
}
|
||||||
details.put(template.getDetailName(), template.getDetailValue());
|
|
||||||
templateResponse.setDetails(details);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// update tag information
|
// update tag information
|
||||||
@ -496,7 +503,6 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
|
|||||||
sc.setParameters("store_id", storeId);
|
sc.setParameters("store_id", storeId);
|
||||||
sc.setParameters("type", TemplateType.USER);
|
sc.setParameters("type", TemplateType.USER);
|
||||||
sc.setParameters("templateState", VirtualMachineTemplate.State.Active);
|
sc.setParameters("templateState", VirtualMachineTemplate.State.Active);
|
||||||
sc.setParameters("public", Boolean.FALSE);
|
|
||||||
return searchIncludingRemoved(sc, null, null, false);
|
return searchIncludingRemoved(sc, null, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -322,8 +322,8 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
|
|||||||
if (vmDetails != null) {
|
if (vmDetails != null) {
|
||||||
Map<String, String> resourceDetails = new HashMap<String, String>();
|
Map<String, String> resourceDetails = new HashMap<String, String>();
|
||||||
for (UserVmDetailVO userVmDetailVO : vmDetails) {
|
for (UserVmDetailVO userVmDetailVO : vmDetails) {
|
||||||
if (!userVmDetailVO.getName().startsWith(ApiConstants.OVF_PROPERTIES) ||
|
if (!userVmDetailVO.getName().startsWith(ApiConstants.PROPERTIES) ||
|
||||||
(UserVmManager.DisplayVMOVFProperties.value() && userVmDetailVO.getName().startsWith(ApiConstants.OVF_PROPERTIES))) {
|
(UserVmManager.DisplayVMOVFProperties.value() && userVmDetailVO.getName().startsWith(ApiConstants.PROPERTIES))) {
|
||||||
resourceDetails.put(userVmDetailVO.getName(), userVmDetailVO.getValue());
|
resourceDetails.put(userVmDetailVO.getName(), userVmDetailVO.getValue());
|
||||||
}
|
}
|
||||||
if ((ApiConstants.BootType.UEFI.toString()).equalsIgnoreCase(userVmDetailVO.getName())) {
|
if ((ApiConstants.BootType.UEFI.toString()).equalsIgnoreCase(userVmDetailVO.getName())) {
|
||||||
|
|||||||
@ -175,6 +175,18 @@ public class ServiceOfferingJoinVO extends BaseViewVO implements InternalIdentit
|
|||||||
@Column(name = "cache_mode")
|
@Column(name = "cache_mode")
|
||||||
String cacheMode;
|
String cacheMode;
|
||||||
|
|
||||||
|
@Column(name = "min_cpu")
|
||||||
|
Integer minCpu;
|
||||||
|
|
||||||
|
@Column(name = "max_cpu")
|
||||||
|
Integer maxCpu;
|
||||||
|
|
||||||
|
@Column(name = "min_memory")
|
||||||
|
Integer minMemory;
|
||||||
|
|
||||||
|
@Column(name = "max_memory")
|
||||||
|
Integer maxMemory;
|
||||||
|
|
||||||
public ServiceOfferingJoinVO() {
|
public ServiceOfferingJoinVO() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,4 +368,20 @@ public class ServiceOfferingJoinVO extends BaseViewVO implements InternalIdentit
|
|||||||
public String getCacheMode() {
|
public String getCacheMode() {
|
||||||
return cacheMode;
|
return cacheMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getMinCpu() {
|
||||||
|
return minCpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMaxCpu() {
|
||||||
|
return maxCpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMinMemory() {
|
||||||
|
return minMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMaxMemory() {
|
||||||
|
return maxMemory;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -231,6 +231,9 @@ public class TemplateJoinVO extends BaseViewWithTagInformationVO implements Cont
|
|||||||
@Column(name = "direct_download")
|
@Column(name = "direct_download")
|
||||||
private boolean directDownload;
|
private boolean directDownload;
|
||||||
|
|
||||||
|
@Column(name = "deploy_as_is")
|
||||||
|
private boolean deployAsIs;
|
||||||
|
|
||||||
public TemplateJoinVO() {
|
public TemplateJoinVO() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,6 +493,10 @@ public class TemplateJoinVO extends BaseViewWithTagInformationVO implements Cont
|
|||||||
return directDownload;
|
return directDownload;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isDeployAsIs() {
|
||||||
|
return deployAsIs;
|
||||||
|
}
|
||||||
|
|
||||||
public Object getParentTemplateId() {
|
public Object getParentTemplateId() {
|
||||||
return parentTemplateId;
|
return parentTemplateId;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -457,7 +457,6 @@ import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd;
|
|||||||
import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd;
|
import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd;
|
||||||
import org.apache.cloudstack.api.command.user.template.ExtractTemplateCmd;
|
import org.apache.cloudstack.api.command.user.template.ExtractTemplateCmd;
|
||||||
import org.apache.cloudstack.api.command.user.template.GetUploadParamsForTemplateCmd;
|
import org.apache.cloudstack.api.command.user.template.GetUploadParamsForTemplateCmd;
|
||||||
import org.apache.cloudstack.api.command.user.template.ListTemplateOVFProperties;
|
|
||||||
import org.apache.cloudstack.api.command.user.template.ListTemplatePermissionsCmd;
|
import org.apache.cloudstack.api.command.user.template.ListTemplatePermissionsCmd;
|
||||||
import org.apache.cloudstack.api.command.user.template.ListTemplatesCmd;
|
import org.apache.cloudstack.api.command.user.template.ListTemplatesCmd;
|
||||||
import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
|
import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
|
||||||
@ -3185,7 +3184,6 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||||||
cmdList.add(RevokeTemplateDirectDownloadCertificateCmd.class);
|
cmdList.add(RevokeTemplateDirectDownloadCertificateCmd.class);
|
||||||
cmdList.add(ListMgmtsCmd.class);
|
cmdList.add(ListMgmtsCmd.class);
|
||||||
cmdList.add(GetUploadParamsForIsoCmd.class);
|
cmdList.add(GetUploadParamsForIsoCmd.class);
|
||||||
cmdList.add(ListTemplateOVFProperties.class);
|
|
||||||
cmdList.add(GetRouterHealthCheckResultsCmd.class);
|
cmdList.add(GetRouterHealthCheckResultsCmd.class);
|
||||||
cmdList.add(StartRollingMaintenanceCmd.class);
|
cmdList.add(StartRollingMaintenanceCmd.class);
|
||||||
cmdList.add(MigrateSecondaryStorageDataCmd.class);
|
cmdList.add(MigrateSecondaryStorageDataCmd.class);
|
||||||
|
|||||||
@ -408,11 +408,11 @@ public class ImageStoreUploadMonitorImpl extends ManagerBase implements ImageSto
|
|||||||
VMTemplateVO templateUpdate = _templateDao.createForUpdate();
|
VMTemplateVO templateUpdate = _templateDao.createForUpdate();
|
||||||
templateUpdate.setSize(answer.getVirtualSize());
|
templateUpdate.setSize(answer.getVirtualSize());
|
||||||
_templateDao.update(tmpTemplate.getId(), templateUpdate);
|
_templateDao.update(tmpTemplate.getId(), templateUpdate);
|
||||||
// For multi-disk OVA, check and create data disk templates
|
// For multi-disk OVA, check and create data disk templates or root disks as details
|
||||||
if (tmpTemplate.getFormat().equals(Storage.ImageFormat.OVA)) {
|
if (tmpTemplate.getFormat().equals(Storage.ImageFormat.OVA)) {
|
||||||
final DataStore store = dataStoreManager.getDataStore(templateDataStore.getDataStoreId(), templateDataStore.getDataStoreRole());
|
final DataStore store = dataStoreManager.getDataStore(templateDataStore.getDataStoreId(), templateDataStore.getDataStoreRole());
|
||||||
final TemplateInfo templateInfo = templateFactory.getTemplate(tmpTemplate.getId(), store);
|
final TemplateInfo templateInfo = templateFactory.getTemplate(tmpTemplate.getId(), store);
|
||||||
if (!templateService.createOvaDataDiskTemplates(templateInfo)) {
|
if (!templateService.createOvaDataDiskTemplates(templateInfo, template.isDeployAsIs())) {
|
||||||
tmpTemplateDataStore.setDownloadState(VMTemplateStorageResourceAssoc.Status.ABANDONED);
|
tmpTemplateDataStore.setDownloadState(VMTemplateStorageResourceAssoc.Status.ABANDONED);
|
||||||
tmpTemplateDataStore.setState(State.Failed);
|
tmpTemplateDataStore.setState(State.Failed);
|
||||||
stateMachine.transitTo(tmpTemplate, VirtualMachineTemplate.Event.OperationFailed, null, _templateDao);
|
stateMachine.transitTo(tmpTemplate, VirtualMachineTemplate.Event.OperationFailed, null, _templateDao);
|
||||||
|
|||||||
@ -52,6 +52,7 @@ public class TemplateProfile {
|
|||||||
Boolean isDynamicallyScalable;
|
Boolean isDynamicallyScalable;
|
||||||
TemplateType templateType;
|
TemplateType templateType;
|
||||||
Boolean directDownload;
|
Boolean directDownload;
|
||||||
|
Boolean deployAsIs;
|
||||||
Long size;
|
Long size;
|
||||||
|
|
||||||
public TemplateProfile(Long templateId, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHvm, String url,
|
public TemplateProfile(Long templateId, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHvm, String url,
|
||||||
@ -95,7 +96,7 @@ public class TemplateProfile {
|
|||||||
Boolean isPublic, Boolean featured, Boolean isExtractable, ImageFormat format, Long guestOsId, List<Long> zoneId,
|
Boolean isPublic, Boolean featured, Boolean isExtractable, ImageFormat format, Long guestOsId, List<Long> zoneId,
|
||||||
|
|
||||||
HypervisorType hypervisorType, String accountName, Long domainId, Long accountId, String chksum, Boolean bootable, String templateTag, Map details,
|
HypervisorType hypervisorType, String accountName, Long domainId, Long accountId, String chksum, Boolean bootable, String templateTag, Map details,
|
||||||
Boolean sshKeyEnabled, Long imageStoreId, Boolean isDynamicallyScalable, TemplateType templateType, Boolean directDownload) {
|
Boolean sshKeyEnabled, Long imageStoreId, Boolean isDynamicallyScalable, TemplateType templateType, Boolean directDownload, Boolean deployAsIs) {
|
||||||
this(templateId,
|
this(templateId,
|
||||||
userId,
|
userId,
|
||||||
name,
|
name,
|
||||||
@ -122,6 +123,7 @@ public class TemplateProfile {
|
|||||||
this.isDynamicallyScalable = isDynamicallyScalable;
|
this.isDynamicallyScalable = isDynamicallyScalable;
|
||||||
this.templateType = templateType;
|
this.templateType = templateType;
|
||||||
this.directDownload = directDownload;
|
this.directDownload = directDownload;
|
||||||
|
this.deployAsIs = deployAsIs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getTemplateId() {
|
public Long getTemplateId() {
|
||||||
@ -331,4 +333,8 @@ public class TemplateProfile {
|
|||||||
public void setSize(Long size) {
|
public void setSize(Long size) {
|
||||||
this.size = size;
|
this.size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isDeployAsIs() {
|
||||||
|
return this.deployAsIs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,4 +46,5 @@ public interface UploadParams {
|
|||||||
boolean isDynamicallyScalable();
|
boolean isDynamicallyScalable();
|
||||||
boolean isRoutingType();
|
boolean isRoutingType();
|
||||||
boolean isDirectDownload();
|
boolean isDirectDownload();
|
||||||
|
boolean isDeployAsIs();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -214,6 +214,11 @@ public abstract class UploadParamsBase implements UploadParams {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDeployAsIs() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void setIso(boolean iso) {
|
void setIso(boolean iso) {
|
||||||
isIso = iso;
|
isIso = iso;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,11 @@ import java.util.concurrent.ExecutionException;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import com.cloud.configuration.Config;
|
||||||
|
import com.cloud.storage.dao.VMTemplateDetailsDao;
|
||||||
|
import com.cloud.utils.db.Transaction;
|
||||||
|
import com.cloud.utils.db.TransactionCallback;
|
||||||
|
import com.cloud.utils.db.TransactionStatus;
|
||||||
import org.apache.cloudstack.agent.directdownload.CheckUrlAnswer;
|
import org.apache.cloudstack.agent.directdownload.CheckUrlAnswer;
|
||||||
import org.apache.cloudstack.agent.directdownload.CheckUrlCommand;
|
import org.apache.cloudstack.agent.directdownload.CheckUrlCommand;
|
||||||
import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd;
|
import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd;
|
||||||
@ -60,7 +65,6 @@ import org.apache.log4j.Logger;
|
|||||||
import com.cloud.agent.AgentManager;
|
import com.cloud.agent.AgentManager;
|
||||||
import com.cloud.agent.api.Answer;
|
import com.cloud.agent.api.Answer;
|
||||||
import com.cloud.alert.AlertManager;
|
import com.cloud.alert.AlertManager;
|
||||||
import com.cloud.configuration.Config;
|
|
||||||
import com.cloud.configuration.Resource.ResourceType;
|
import com.cloud.configuration.Resource.ResourceType;
|
||||||
import com.cloud.dc.DataCenterVO;
|
import com.cloud.dc.DataCenterVO;
|
||||||
import com.cloud.dc.dao.DataCenterDao;
|
import com.cloud.dc.dao.DataCenterDao;
|
||||||
@ -89,9 +93,6 @@ import com.cloud.utils.Pair;
|
|||||||
import com.cloud.utils.UriUtils;
|
import com.cloud.utils.UriUtils;
|
||||||
import com.cloud.utils.db.DB;
|
import com.cloud.utils.db.DB;
|
||||||
import com.cloud.utils.db.EntityManager;
|
import com.cloud.utils.db.EntityManager;
|
||||||
import com.cloud.utils.db.Transaction;
|
|
||||||
import com.cloud.utils.db.TransactionCallback;
|
|
||||||
import com.cloud.utils.db.TransactionStatus;
|
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
|
||||||
public class HypervisorTemplateAdapter extends TemplateAdapterBase {
|
public class HypervisorTemplateAdapter extends TemplateAdapterBase {
|
||||||
@ -126,6 +127,8 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
|
|||||||
ResourceManager resourceManager;
|
ResourceManager resourceManager;
|
||||||
@Inject
|
@Inject
|
||||||
VMTemplateDao templateDao;
|
VMTemplateDao templateDao;
|
||||||
|
@Inject
|
||||||
|
private VMTemplateDetailsDao templateDetailsDao;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@ -241,12 +244,14 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
|
|||||||
|
|
||||||
private void createTemplateWithinZone(Long zId, TemplateProfile profile, VMTemplateVO template) {
|
private void createTemplateWithinZone(Long zId, TemplateProfile profile, VMTemplateVO template) {
|
||||||
// find all eligible image stores for this zone scope
|
// find all eligible image stores for this zone scope
|
||||||
List<DataStore> imageStores = storeMgr.getImageStoresByScopeExcludingReadOnly(new ZoneScope(zId));
|
List<DataStore> imageStores = storeMgr.getImageStoresByScope(new ZoneScope(zId));
|
||||||
if (imageStores == null || imageStores.size() == 0) {
|
if (imageStores == null || imageStores.size() == 0) {
|
||||||
throw new CloudRuntimeException("Unable to find image store to download template " + profile.getTemplate());
|
throw new CloudRuntimeException("Unable to find image store to download template " + profile.getTemplate());
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<Long> zoneSet = new HashSet<Long>();
|
Set<Long> zoneSet = new HashSet<Long>();
|
||||||
|
Collections.shuffle(imageStores);
|
||||||
|
// For private templates choose a random store. TODO - Have a better algorithm based on size, no. of objects, load etc.
|
||||||
for (DataStore imageStore : imageStores) {
|
for (DataStore imageStore : imageStores) {
|
||||||
// skip data stores for a disabled zone
|
// skip data stores for a disabled zone
|
||||||
Long zoneId = imageStore.getScope().getScopeId();
|
Long zoneId = imageStore.getScope().getScopeId();
|
||||||
@ -306,7 +311,7 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
|
|||||||
zoneId = profile.getZoneIdList().get(0);
|
zoneId = profile.getZoneIdList().get(0);
|
||||||
|
|
||||||
// find all eligible image stores for this zone scope
|
// find all eligible image stores for this zone scope
|
||||||
List<DataStore> imageStores = storeMgr.getImageStoresByScopeExcludingReadOnly(new ZoneScope(zoneId));
|
List<DataStore> imageStores = storeMgr.getImageStoresByScope(new ZoneScope(zoneId));
|
||||||
if (imageStores == null || imageStores.size() == 0) {
|
if (imageStores == null || imageStores.size() == 0) {
|
||||||
throw new CloudRuntimeException("Unable to find image store to download template " + profile.getTemplate());
|
throw new CloudRuntimeException("Unable to find image store to download template " + profile.getTemplate());
|
||||||
}
|
}
|
||||||
@ -590,6 +595,9 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
|
|||||||
Pair<Class<?>, Long> tmplt = new Pair<Class<?>, Long>(VirtualMachineTemplate.class, template.getId());
|
Pair<Class<?>, Long> tmplt = new Pair<Class<?>, Long>(VirtualMachineTemplate.class, template.getId());
|
||||||
_messageBus.publish(_name, EntityManager.MESSAGE_REMOVE_ENTITY_EVENT, PublishScope.LOCAL, tmplt);
|
_messageBus.publish(_name, EntityManager.MESSAGE_REMOVE_ENTITY_EVENT, PublishScope.LOCAL, tmplt);
|
||||||
|
|
||||||
|
// Remove template details
|
||||||
|
templateDetailsDao.removeDetails(template.getId());
|
||||||
|
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
|
|
||||||
|
|||||||
@ -72,13 +72,12 @@ public interface TemplateAdapter extends Adapter {
|
|||||||
|
|
||||||
boolean delete(TemplateProfile profile);
|
boolean delete(TemplateProfile profile);
|
||||||
|
|
||||||
TemplateProfile prepare(boolean isIso, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url,
|
TemplateProfile prepare(boolean isIso, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url, Boolean isPublic,
|
||||||
Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, List<Long> zoneId, HypervisorType hypervisorType, String accountName,
|
Boolean featured, Boolean isExtractable, String format, Long guestOSId, List<Long> zoneId, HypervisorType hypervisorType, String accountName, Long domainId, String chksum, Boolean bootable, Map details, boolean directDownload,
|
||||||
Long domainId, String chksum, Boolean bootable, Map details, boolean directDownload) throws ResourceAllocationException;
|
boolean deployAsIs) throws ResourceAllocationException;
|
||||||
|
|
||||||
TemplateProfile prepare(boolean isIso, long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url,
|
TemplateProfile prepare(boolean isIso, long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url, Boolean isPublic,
|
||||||
Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, List<Long> zoneId, HypervisorType hypervisorType, String chksum,
|
Boolean featured, Boolean isExtractable, String format, Long guestOSId, List<Long> zoneId, HypervisorType hypervisorType, String chksum, Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshKeyEnabled, String imageStoreUuid, Boolean isDynamicallyScalable,
|
||||||
Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshKeyEnabled, String imageStoreUuid, Boolean isDynamicallyScalable,
|
TemplateType templateType, boolean directDownload, boolean deployAsIs) throws ResourceAllocationException;
|
||||||
TemplateType templateType, boolean directDownload) throws ResourceAllocationException;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -129,16 +129,16 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||||||
@Override
|
@Override
|
||||||
public TemplateProfile prepare(boolean isIso, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url,
|
public TemplateProfile prepare(boolean isIso, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url,
|
||||||
Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, List<Long> zoneId, HypervisorType hypervisorType, String accountName,
|
Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, List<Long> zoneId, HypervisorType hypervisorType, String accountName,
|
||||||
Long domainId, String chksum, Boolean bootable, Map details, boolean directDownload) throws ResourceAllocationException {
|
Long domainId, String chksum, Boolean bootable, Map details, boolean directDownload, boolean deployAsIs) throws ResourceAllocationException {
|
||||||
return prepare(isIso, userId, name, displayText, bits, passwordEnabled, requiresHVM, url, isPublic, featured, isExtractable, format, guestOSId, zoneId,
|
return prepare(isIso, userId, name, displayText, bits, passwordEnabled, requiresHVM, url, isPublic, featured, isExtractable, format, guestOSId, zoneId,
|
||||||
hypervisorType, chksum, bootable, null, null, details, false, null, false, TemplateType.USER, directDownload);
|
hypervisorType, chksum, bootable, null, null, details, false, null, false, TemplateType.USER, directDownload, deployAsIs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TemplateProfile prepare(boolean isIso, long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url,
|
public TemplateProfile prepare(boolean isIso, long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url,
|
||||||
Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, List<Long> zoneIdList, HypervisorType hypervisorType, String chksum,
|
Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, List<Long> zoneIdList, HypervisorType hypervisorType, String chksum,
|
||||||
Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshkeyEnabled, String imageStoreUuid, Boolean isDynamicallyScalable,
|
Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshkeyEnabled, String imageStoreUuid, Boolean isDynamicallyScalable,
|
||||||
TemplateType templateType, boolean directDownload) throws ResourceAllocationException {
|
TemplateType templateType, boolean directDownload, boolean deployAsIs) throws ResourceAllocationException {
|
||||||
//Long accountId = null;
|
//Long accountId = null;
|
||||||
// parameters verification
|
// parameters verification
|
||||||
|
|
||||||
@ -257,7 +257,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||||||
CallContext.current().setEventDetails("Id: " + id + " name: " + name);
|
CallContext.current().setEventDetails("Id: " + id + " name: " + name);
|
||||||
return new TemplateProfile(id, userId, name, displayText, bits, passwordEnabled, requiresHVM, url, isPublic, featured, isExtractable, imgfmt, guestOSId, zoneIdList,
|
return new TemplateProfile(id, userId, name, displayText, bits, passwordEnabled, requiresHVM, url, isPublic, featured, isExtractable, imgfmt, guestOSId, zoneIdList,
|
||||||
hypervisorType, templateOwner.getAccountName(), templateOwner.getDomainId(), templateOwner.getAccountId(), chksum, bootable, templateTag, details,
|
hypervisorType, templateOwner.getAccountName(), templateOwner.getDomainId(), templateOwner.getAccountId(), chksum, bootable, templateTag, details,
|
||||||
sshkeyEnabled, null, isDynamicallyScalable, templateType, directDownload);
|
sshkeyEnabled, null, isDynamicallyScalable, templateType, directDownload, deployAsIs);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,7 +285,8 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||||||
|
|
||||||
return prepare(false, CallContext.current().getCallingUserId(), cmd.getTemplateName(), cmd.getDisplayText(), cmd.getBits(), cmd.isPasswordEnabled(), cmd.getRequiresHvm(),
|
return prepare(false, CallContext.current().getCallingUserId(), cmd.getTemplateName(), cmd.getDisplayText(), cmd.getBits(), cmd.isPasswordEnabled(), cmd.getRequiresHvm(),
|
||||||
cmd.getUrl(), cmd.isPublic(), cmd.isFeatured(), cmd.isExtractable(), cmd.getFormat(), cmd.getOsTypeId(), zoneId, hypervisorType, cmd.getChecksum(), true,
|
cmd.getUrl(), cmd.isPublic(), cmd.isFeatured(), cmd.isExtractable(), cmd.getFormat(), cmd.getOsTypeId(), zoneId, hypervisorType, cmd.getChecksum(), true,
|
||||||
cmd.getTemplateTag(), owner, cmd.getDetails(), cmd.isSshKeyEnabled(), null, cmd.isDynamicallyScalable(), isRouting ? TemplateType.ROUTING : TemplateType.USER, cmd.isDirectDownload());
|
cmd.getTemplateTag(), owner, cmd.getDetails(), cmd.isSshKeyEnabled(), null, cmd.isDynamicallyScalable(), isRouting ? TemplateType.ROUTING : TemplateType.USER,
|
||||||
|
cmd.isDirectDownload(), cmd.isDeployAsIs());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,7 +317,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||||||
params.isExtractable(), params.getFormat(), params.getGuestOSId(), zoneList,
|
params.isExtractable(), params.getFormat(), params.getGuestOSId(), zoneList,
|
||||||
params.getHypervisorType(), params.getChecksum(), params.isBootable(), params.getTemplateTag(), owner,
|
params.getHypervisorType(), params.getChecksum(), params.isBootable(), params.getTemplateTag(), owner,
|
||||||
params.getDetails(), params.isSshKeyEnabled(), params.getImageStoreUuid(),
|
params.getDetails(), params.isSshKeyEnabled(), params.getImageStoreUuid(),
|
||||||
params.isDynamicallyScalable(), params.isRoutingType() ? TemplateType.ROUTING : TemplateType.USER, params.isDirectDownload());
|
params.isDynamicallyScalable(), params.isRoutingType() ? TemplateType.ROUTING : TemplateType.USER, params.isDirectDownload(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -358,7 +359,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||||||
|
|
||||||
return prepare(true, CallContext.current().getCallingUserId(), cmd.getIsoName(), cmd.getDisplayText(), 64, cmd.isPasswordEnabled(), true, cmd.getUrl(), cmd.isPublic(),
|
return prepare(true, CallContext.current().getCallingUserId(), cmd.getIsoName(), cmd.getDisplayText(), 64, cmd.isPasswordEnabled(), true, cmd.getUrl(), cmd.isPublic(),
|
||||||
cmd.isFeatured(), cmd.isExtractable(), ImageFormat.ISO.toString(), cmd.getOsTypeId(), zoneList, HypervisorType.None, cmd.getChecksum(), cmd.isBootable(), null,
|
cmd.isFeatured(), cmd.isExtractable(), ImageFormat.ISO.toString(), cmd.getOsTypeId(), zoneList, HypervisorType.None, cmd.getChecksum(), cmd.isBootable(), null,
|
||||||
owner, null, false, cmd.getImageStoreUuid(), cmd.isDynamicallyScalable(), TemplateType.USER, cmd.isDirectDownload());
|
owner, null, false, cmd.getImageStoreUuid(), cmd.isDynamicallyScalable(), TemplateType.USER, cmd.isDirectDownload(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected VMTemplateVO persistTemplate(TemplateProfile profile, VirtualMachineTemplate.State initialState) {
|
protected VMTemplateVO persistTemplate(TemplateProfile profile, VirtualMachineTemplate.State initialState) {
|
||||||
@ -367,7 +368,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||||||
new VMTemplateVO(profile.getTemplateId(), profile.getName(), profile.getFormat(), profile.isPublic(), profile.isFeatured(), profile.isExtractable(),
|
new VMTemplateVO(profile.getTemplateId(), profile.getName(), profile.getFormat(), profile.isPublic(), profile.isFeatured(), profile.isExtractable(),
|
||||||
profile.getTemplateType(), profile.getUrl(), profile.isRequiresHVM(), profile.getBits(), profile.getAccountId(), profile.getCheckSum(),
|
profile.getTemplateType(), profile.getUrl(), profile.isRequiresHVM(), profile.getBits(), profile.getAccountId(), profile.getCheckSum(),
|
||||||
profile.getDisplayText(), profile.isPasswordEnabled(), profile.getGuestOsId(), profile.isBootable(), profile.getHypervisorType(),
|
profile.getDisplayText(), profile.isPasswordEnabled(), profile.getGuestOsId(), profile.isBootable(), profile.getHypervisorType(),
|
||||||
profile.getTemplateTag(), profile.getDetails(), profile.isSshKeyEnabled(), profile.IsDynamicallyScalable(), profile.isDirectDownload());
|
profile.getTemplateTag(), profile.getDetails(), profile.isSshKeyEnabled(), profile.IsDynamicallyScalable(), profile.isDirectDownload(), profile.isDeployAsIs());
|
||||||
template.setState(initialState);
|
template.setState(initialState);
|
||||||
|
|
||||||
if (profile.isDirectDownload()) {
|
if (profile.isDirectDownload()) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user