Handle guest OS read from deploy-as-is OVF descriptor

This commit is contained in:
nvazquez 2020-09-25 01:41:47 -03:00 committed by Harikrishna Patnala
parent 89aa25d023
commit 41354227e2
18 changed files with 684 additions and 367 deletions

View File

@ -46,6 +46,7 @@ import com.cloud.agent.api.to.deployasis.OVFVirtualHardwareItemTO;
import com.cloud.agent.api.to.deployasis.OVFVirtualHardwareSectionTO;
import com.cloud.configuration.Resource.ResourceType;
import com.cloud.exception.InternalErrorException;
import com.cloud.utils.Pair;
import com.cloud.utils.compression.CompressionUtil;
import com.cloud.agent.api.to.deployasis.OVFNetworkTO;
import org.apache.commons.collections.CollectionUtils;
@ -217,6 +218,12 @@ public class OVFHelper {
return getConfigurableOVFPropertiesFromDocument(doc);
}
protected Pair<String, String> getOperatingSystemInfoFromXmlString(final String ovfString) throws ParserConfigurationException, IOException, SAXException {
InputSource is = new InputSource(new StringReader(ovfString));
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
return getOperatingSystemInfoFromDocument(doc);
}
protected List<OVFConfigurationTO> getOVFDeploymentOptionsFromXmlString(final String ovfString) throws ParserConfigurationException, IOException, SAXException {
InputSource is = new InputSource(new StringReader(ovfString));
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
@ -229,6 +236,12 @@ public class OVFHelper {
return getVirtualHardwareItemsFromDocumentTree(doc);
}
protected OVFVirtualHardwareSectionTO getVirtualHardwareSectionFromXmlString(final String ovfString) throws ParserConfigurationException, IOException, SAXException {
InputSource is = new InputSource(new StringReader(ovfString));
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
return getVirtualHardwareSectionFromDocument(doc);
}
protected List<OVFEulaSectionTO> getOVFEulaSectionFromXmlString(final String ovfString) throws ParserConfigurationException, IOException, SAXException {
InputSource is = new InputSource(new StringReader(ovfString));
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
@ -726,7 +739,26 @@ public class OVFHelper {
if (CollectionUtils.isNotEmpty(items)) {
commonItems = items.stream().filter(x -> StringUtils.isBlank(x.getConfigurationIds())).collect(Collectors.toList());
}
return new OVFVirtualHardwareSectionTO(configurations, commonItems);
String minimumHardwareVersion = getMinimumHardwareVersionFromDocumentTree(doc);
return new OVFVirtualHardwareSectionTO(configurations, commonItems, minimumHardwareVersion);
}
private String getMinimumHardwareVersionFromDocumentTree(Document doc) {
String version = null;
if (doc != null) {
NodeList systemNodeList = doc.getElementsByTagName("System");
if (systemNodeList.getLength() != 0) {
Node systemItem = systemNodeList.item(0);
String hardwareVersions = getChildNodeValue(systemItem, "VirtualSystemType");
if (StringUtils.isNotBlank(hardwareVersions)) {
String[] versions = hardwareVersions.split(",");
// Order the hardware versions and retrieve the minimum version
List<String> versionsList = Arrays.stream(versions).sorted().collect(Collectors.toList());
version = versionsList.get(0);
}
}
}
return version;
}
private List<OVFConfigurationTO> getDeploymentOptionsFromDocumentTree(Document doc) {
@ -869,6 +901,21 @@ public class OVFHelper {
return eulas;
}
public Pair<String, String> getOperatingSystemInfoFromDocument(Document doc) {
if (doc == null) {
return null;
}
NodeList guesOsList = doc.getElementsByTagName("OperatingSystemSection");
if (guesOsList.getLength() == 0) {
return null;
}
Node guestOsNode = guesOsList.item(0);
Element guestOsElement = (Element) guestOsNode;
String osType = getNodeAttribute(guestOsElement, "vmw", "osType");
String description = getChildNodeValue(guestOsNode, "Description");
return new Pair<>(osType, description);
}
class OVFFile {
// <File ovf:href="i-2-8-VM-disk2.vmdk" ovf:id="file1" ovf:size="69120" />
public String _href;

View File

@ -0,0 +1,95 @@
//
// 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;
import com.cloud.agent.api.LogLevel;
import com.cloud.agent.api.to.deployasis.OVFEulaSectionTO;
import com.cloud.agent.api.to.deployasis.OVFNetworkTO;
import com.cloud.agent.api.to.deployasis.OVFPropertyTO;
import com.cloud.agent.api.to.deployasis.OVFVirtualHardwareSectionTO;
import com.cloud.utils.Pair;
import java.util.List;
public class OVFInformationTO {
@LogLevel(LogLevel.Log4jLevel.Off)
private List<OVFPropertyTO> properties;
@LogLevel(LogLevel.Log4jLevel.Off)
private List<OVFNetworkTO> networks;
@LogLevel(LogLevel.Log4jLevel.Off)
private List<DatadiskTO> disks;
@LogLevel(LogLevel.Log4jLevel.Off)
private OVFVirtualHardwareSectionTO hardwareSection;
@LogLevel(LogLevel.Log4jLevel.Off)
private List<OVFEulaSectionTO> eulaSections;
@LogLevel(LogLevel.Log4jLevel.Off)
private Pair<String, String> guestOsInfo;
public OVFInformationTO() {
}
public List<OVFPropertyTO> getProperties() {
return properties;
}
public void setProperties(List<OVFPropertyTO> properties) {
this.properties = properties;
}
public List<OVFNetworkTO> getNetworks() {
return networks;
}
public void setNetworks(List<OVFNetworkTO> networks) {
this.networks = networks;
}
public List<DatadiskTO> getDisks() {
return disks;
}
public void setDisks(List<DatadiskTO> disks) {
this.disks = disks;
}
public OVFVirtualHardwareSectionTO getHardwareSection() {
return hardwareSection;
}
public void setHardwareSection(OVFVirtualHardwareSectionTO hardwareSection) {
this.hardwareSection = hardwareSection;
}
public List<OVFEulaSectionTO> getEulaSections() {
return eulaSections;
}
public void setEulaSections(List<OVFEulaSectionTO> eulaSections) {
this.eulaSections = eulaSections;
}
public Pair<String, String> getGuestOsInfo() {
return guestOsInfo;
}
public void setGuestOsInfo(Pair<String, String> guestOsInfo) {
this.guestOsInfo = guestOsInfo;
}
}

View File

@ -25,12 +25,15 @@ public class OVFVirtualHardwareSectionTO implements TemplateDeployAsIsInformatio
public OVFVirtualHardwareSectionTO() {
}
private String minimiumHardwareVersion;
private List<OVFConfigurationTO> configurations;
private List<OVFVirtualHardwareItemTO> commonHardwareItems;
public OVFVirtualHardwareSectionTO(List<OVFConfigurationTO> configurations, List<OVFVirtualHardwareItemTO> commonHardwareItems) {
public OVFVirtualHardwareSectionTO(List<OVFConfigurationTO> configurations, List<OVFVirtualHardwareItemTO> commonHardwareItems,
String minimumHardwareVersion) {
this.configurations = configurations;
this.commonHardwareItems = commonHardwareItems;
this.minimiumHardwareVersion = minimumHardwareVersion;
}
public List<OVFConfigurationTO> getConfigurations() {
@ -40,4 +43,8 @@ public class OVFVirtualHardwareSectionTO implements TemplateDeployAsIsInformatio
public List<OVFVirtualHardwareItemTO> getCommonHardwareItems() {
return commonHardwareItems;
}
public String getMinimiumHardwareVersion() {
return minimiumHardwareVersion;
}
}

View File

@ -24,4 +24,5 @@ public interface DeployAsIsConstants {
String HARDWARE_ITEM_PREFIX = "hardware-item-";
String EULA_PREFIX = "eula-";
String DEFAULT_GUEST_OS_DEPLOY_AS_IS = "OVF Configured OS";
}

View File

@ -347,5 +347,9 @@ public class RegisterTemplateCmd extends BaseCmd implements UserCmd {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
"Parameter directdownload is only allowed for KVM templates");
}
if (isDeployAsIs() && !getHypervisor().equalsIgnoreCase(Hypervisor.HypervisorType.VMware.toString())) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Parameter deployasis is only allowed for VMware templates");
}
}
}

View File

@ -20,6 +20,8 @@ import com.cloud.agent.api.to.deployasis.OVFConfigurationTO;
import com.cloud.agent.api.to.deployasis.OVFEulaSectionTO;
import com.cloud.agent.api.to.deployasis.OVFPropertyTO;
import com.cloud.agent.api.to.deployasis.OVFVirtualHardwareItemTO;
import com.cloud.agent.api.to.deployasis.OVFVirtualHardwareSectionTO;
import com.cloud.utils.Pair;
import org.junit.Assert;
import org.junit.Test;
import org.xml.sax.SAXException;
@ -62,204 +64,210 @@ public class OVFHelperTest {
" </DeploymentOptionSection>";
private String ovfFileVirtualHardwareSection =
"<VirtualSystem>\n" +
"<OperatingSystemSection ovf:id=\"100\" vmw:osType=\"other26xLinux64Guest\">\n" +
" <Info>The kind of installed guest operating system</Info>\n" +
" <Description>Other 2.6x Linux (64-bit)</Description>\n" +
"</OperatingSystemSection>\n" +
"<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>";
" <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>\n" +
"</VirtualSystem>";
private String eulaSections =
"<VirtualSystem>\n" +
@ -729,4 +737,17 @@ public class OVFHelperTest {
List<OVFPropertyTO> props = ovfHelper.getOVFPropertiesFromXmlString(productSectionWithCategories);
Assert.assertEquals(18, props.size());
}
@Test
public void testGetOperatingSystemInfo() throws IOException, SAXException, ParserConfigurationException {
Pair<String, String> guestOsPair = ovfHelper.getOperatingSystemInfoFromXmlString(ovfFileVirtualHardwareSection);
Assert.assertEquals("other26xLinux64Guest", guestOsPair.first());
Assert.assertEquals("Other 2.6x Linux (64-bit)", guestOsPair.second());
}
@Test
public void testGetMinimumHardwareVersion() throws IOException, SAXException, ParserConfigurationException {
OVFVirtualHardwareSectionTO hardwareSection = ovfHelper.getVirtualHardwareSectionFromXmlString(ovfFileVirtualHardwareSection);
Assert.assertEquals("vmx-08", hardwareSection.getMinimiumHardwareVersion());
}
}

View File

@ -20,18 +20,13 @@
package com.cloud.agent.api.storage;
import java.io.File;
import java.util.List;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.LogLevel;
import com.cloud.agent.api.to.DatadiskTO;
import com.cloud.agent.api.to.deployasis.OVFEulaSectionTO;
import com.cloud.agent.api.to.deployasis.OVFPropertyTO;
import com.cloud.agent.api.to.deployasis.OVFVirtualHardwareSectionTO;
import com.cloud.agent.api.to.OVFInformationTO;
import com.cloud.storage.VMTemplateStorageResourceAssoc;
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
import com.cloud.agent.api.to.deployasis.OVFNetworkTO;
public class DownloadAnswer extends Answer {
private String jobId;
@ -45,15 +40,7 @@ public class DownloadAnswer extends Answer {
private String checkSum;
@LogLevel(LogLevel.Log4jLevel.Off)
private List<OVFPropertyTO> ovfProperties;
@LogLevel(LogLevel.Log4jLevel.Off)
private List<OVFNetworkTO> networkRequirements;
@LogLevel(LogLevel.Log4jLevel.Off)
private List<DatadiskTO> disks;
@LogLevel(LogLevel.Log4jLevel.Off)
private OVFVirtualHardwareSectionTO ovfHardwareSection;
@LogLevel(LogLevel.Log4jLevel.Off)
private List<OVFEulaSectionTO> eulaSections;
private OVFInformationTO ovfInformationTO;
public String getCheckSum() {
return checkSum;
@ -164,43 +151,11 @@ public class DownloadAnswer extends Answer {
return templatePhySicalSize;
}
public List<OVFPropertyTO> getOvfProperties() {
return ovfProperties;
public OVFInformationTO getOvfInformationTO() {
return ovfInformationTO;
}
public void setOvfProperties(List<OVFPropertyTO> ovfProperties) {
this.ovfProperties = ovfProperties;
}
public List<OVFNetworkTO> getNetworkRequirements() {
return networkRequirements;
}
public void setNetworkRequirements(List<OVFNetworkTO> 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;
public void setOvfInformationTO(OVFInformationTO ovfInformationTO) {
this.ovfInformationTO = ovfInformationTO;
}
}

View File

@ -28,6 +28,7 @@ import javax.naming.ConfigurationException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import com.cloud.agent.api.to.OVFInformationTO;
import com.cloud.agent.api.to.deployasis.OVFConfigurationTO;
import com.cloud.agent.api.to.deployasis.OVFEulaSectionTO;
import com.cloud.agent.api.to.deployasis.OVFPropertyTO;
@ -35,6 +36,7 @@ import com.cloud.agent.api.to.deployasis.OVFVirtualHardwareItemTO;
import com.cloud.agent.api.to.deployasis.OVFVirtualHardwareSectionTO;
import com.cloud.agent.api.to.deployasis.OVFNetworkTO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@ -107,30 +109,34 @@ public class OVAProcessor extends AdapterBase implements Processor {
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;
}
OVFInformationTO ovfInformationTO = createOvfInformationTO(ovfHelper, doc, ovfFilePath);
info.ovfInformationTO = ovfInformationTO;
}
private OVFInformationTO createOvfInformationTO(OVFHelper ovfHelper, Document doc, String ovfFilePath) throws InternalErrorException {
OVFInformationTO ovfInformationTO = new OVFInformationTO();
List<DatadiskTO> disks = ovfHelper.getOVFVolumeInfoFromFile(ovfFilePath, doc, null);
if (CollectionUtils.isNotEmpty(disks)) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace(String.format("Found %d disks in template %s", disks.size(), ovfFilePath));
}
ovfInformationTO.setDisks(disks);
}
List<OVFNetworkTO> nets = ovfHelper.getNetPrerequisitesFromDocument(doc);
if (CollectionUtils.isNotEmpty(nets)) {
LOGGER.info("Found " + nets.size() + " prerequisite networks");
info.networks = nets;
ovfInformationTO.setNetworks(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;
ovfInformationTO.setProperties(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)) {
@ -140,12 +146,21 @@ public class OVAProcessor extends AdapterBase implements Processor {
if (CollectionUtils.isNotEmpty(hardwareItems)) {
LOGGER.info("Found " + hardwareItems.size() + " virtual hardware items");
}
info.hardwareSection = hardwareSection;
if (StringUtils.isNotBlank(hardwareSection.getMinimiumHardwareVersion())) {
LOGGER.info("Found minimum hardware version " + hardwareSection.getMinimiumHardwareVersion());
}
ovfInformationTO.setHardwareSection(hardwareSection);
List<OVFEulaSectionTO> eulaSections = ovfHelper.getEulaSectionsFromDocument(doc);
if (CollectionUtils.isNotEmpty(eulaSections)) {
LOGGER.info("Found " + eulaSections.size() + " license agreements");
info.eulaSections = eulaSections;
ovfInformationTO.setEulaSections(eulaSections);
}
Pair<String, String> guestOsPair = ovfHelper.getOperatingSystemInfoFromDocument(doc);
if (guestOsPair != null) {
LOGGER.info("Found guest OS information: " + guestOsPair.first() + " - " + guestOsPair.second());
ovfInformationTO.setGuestOsInfo(guestOsPair);
}
return ovfInformationTO;
}
private void setFileSystemAccessRights(String templatePath) {

View File

@ -21,16 +21,11 @@ package com.cloud.storage.template;
import java.io.File;
import java.io.IOException;
import java.util.List;
import com.cloud.agent.api.to.deployasis.OVFEulaSectionTO;
import com.cloud.agent.api.to.deployasis.OVFPropertyTO;
import com.cloud.agent.api.to.deployasis.OVFVirtualHardwareSectionTO;
import com.cloud.agent.api.to.DatadiskTO;
import com.cloud.agent.api.to.OVFInformationTO;
import com.cloud.exception.InternalErrorException;
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.utils.component.Adapter;
import com.cloud.agent.api.to.deployasis.OVFNetworkTO;
/**
* Generic interface to process different types of image formats
@ -58,11 +53,7 @@ public interface Processor extends Adapter {
public long virtualSize;
public String filename;
public boolean isCorrupted;
public List<OVFPropertyTO> ovfProperties;
public List<OVFNetworkTO> networks;
public List<DatadiskTO> disks;
public OVFVirtualHardwareSectionTO hardwareSection;
public List<OVFEulaSectionTO> eulaSections;
public OVFInformationTO ovfInformationTO;
}
long getVirtualSize(File file) throws IOException;

View File

@ -17,6 +17,7 @@
package com.cloud.agent.api.storage;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.to.OVFInformationTO;
import com.cloud.agent.api.to.deployasis.OVFPropertyTO;
import com.cloud.serializer.GsonHelper;
import com.cloud.storage.VMTemplateStorageResourceAssoc;
@ -49,8 +50,10 @@ public class DownloadAnswerTest {
List<OVFNetworkTO> networks = new ArrayList<>();
networks.add(new OVFNetworkTO());
answer.setOvfProperties(properties);
answer.setNetworkRequirements(networks);
OVFInformationTO informationTO = new OVFInformationTO();
informationTO.setProperties(properties);
informationTO.setNetworks(networks);
answer.setOvfInformationTO(informationTO);
String json = gson.toJson(answer);
Answer received = gson.fromJson(json, Answer.class);

View File

@ -21,4 +21,5 @@ import com.cloud.utils.db.GenericDao;
public interface GuestOSCategoryDao extends GenericDao<GuestOSCategoryVO, Long> {
GuestOSCategoryVO findByCategoryName(String categoryName);
}

View File

@ -16,7 +16,8 @@
// under the License.
package com.cloud.storage.dao;
import com.cloud.utils.db.QueryBuilder;
import com.cloud.utils.db.SearchCriteria;
import org.springframework.stereotype.Component;
import com.cloud.storage.GuestOSCategoryVO;
@ -29,4 +30,10 @@ public class GuestOSCategoryDaoImpl extends GenericDaoBase<GuestOSCategoryVO, Lo
}
@Override
public GuestOSCategoryVO findByCategoryName(String categoryName) {
final QueryBuilder<GuestOSCategoryVO> sc = QueryBuilder.create(GuestOSCategoryVO.class);
sc.and(sc.entity().getName(), SearchCriteria.Op.EQ, categoryName);
return sc.find();
}
}

View File

@ -20,6 +20,8 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.storage.GuestOSHypervisorVO;
import com.cloud.utils.db.GenericDao;
import java.util.List;
public interface GuestOSHypervisorDao extends GenericDao<GuestOSHypervisorVO, Long> {
HypervisorType findHypervisorTypeByGuestOsId(long guestOsId);
@ -31,4 +33,9 @@ public interface GuestOSHypervisorDao extends GenericDao<GuestOSHypervisorVO, Lo
GuestOSHypervisorVO findByOsIdAndHypervisorAndUserDefined(long guestOsId, String hypervisorType, String hypervisorVersion, boolean isUserDefined);
GuestOSHypervisorVO findByOsNameAndHypervisor(String guestOsName, String hypervisorType, String hypervisorVersion);
List<GuestOSHypervisorVO> listByOsNameAndHypervisorMinimumVersion(String guestOsName, String hypervisorType,
String minHypervisorVersion);
List<String> listHypervisorSupportedVersionsFromMinimumVersion(String hypervisorType, String hypervisorVersion);
}

View File

@ -16,9 +16,11 @@
// under the License.
package com.cloud.storage.dao;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.cloud.utils.db.QueryBuilder;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Component;
@ -36,6 +38,7 @@ public class GuestOSHypervisorDaoImpl extends GenericDaoBase<GuestOSHypervisorVO
protected final SearchBuilder<GuestOSHypervisorVO> mappingSearch;
protected final SearchBuilder<GuestOSHypervisorVO> userDefinedMappingSearch;
protected final SearchBuilder<GuestOSHypervisorVO> guestOsNameSearch;
protected final SearchBuilder<GuestOSHypervisorVO> availableHypervisorVersionSearch;
protected GuestOSHypervisorDaoImpl() {
guestOsSearch = createSearchBuilder();
@ -60,6 +63,15 @@ public class GuestOSHypervisorDaoImpl extends GenericDaoBase<GuestOSHypervisorVO
guestOsNameSearch.and("hypervisor_type", guestOsNameSearch.entity().getHypervisorType(), SearchCriteria.Op.EQ);
guestOsNameSearch.and("hypervisor_version", guestOsNameSearch.entity().getHypervisorVersion(), SearchCriteria.Op.EQ);
guestOsNameSearch.done();
availableHypervisorVersionSearch = createSearchBuilder();
availableHypervisorVersionSearch.and("hypervisor_type",
availableHypervisorVersionSearch.entity().getHypervisorType(), SearchCriteria.Op.EQ);
availableHypervisorVersionSearch.and("hypervisor_version",
availableHypervisorVersionSearch.entity().getHypervisorVersion(), SearchCriteria.Op.GTEQ);
availableHypervisorVersionSearch.select(null, SearchCriteria.Func.DISTINCT,
availableHypervisorVersionSearch.entity().getHypervisorVersion());
availableHypervisorVersionSearch.done();
}
@Override
@ -121,4 +133,29 @@ public class GuestOSHypervisorDaoImpl extends GenericDaoBase<GuestOSHypervisorVO
return CollectionUtils.isNotEmpty(results) ? results.get(0) : null;
}
@Override
public List<GuestOSHypervisorVO> listByOsNameAndHypervisorMinimumVersion(String guestOsName, String hypervisorType,
String minHypervisorVersion) {
final QueryBuilder<GuestOSHypervisorVO> sc = QueryBuilder.create(GuestOSHypervisorVO.class);
sc.and(sc.entity().getGuestOsName(), SearchCriteria.Op.EQ, guestOsName);
sc.and(sc.entity().getHypervisorType(), SearchCriteria.Op.EQ, hypervisorType);
sc.and(sc.entity().getHypervisorVersion(), SearchCriteria.Op.GTEQ, minHypervisorVersion);
sc.and(sc.entity().getHypervisorVersion(), SearchCriteria.Op.NEQ, "default");
return sc.list();
}
@Override
public List<String> listHypervisorSupportedVersionsFromMinimumVersion(String hypervisorType, String hypervisorVersion) {
List<String> versions = new ArrayList<>();
SearchCriteria<GuestOSHypervisorVO> sc = availableHypervisorVersionSearch.create();
sc.setParameters("hypervisor_type", hypervisorType);
sc.setParameters("hypervisor_version", hypervisorVersion);
Filter filter = new Filter(GuestOSHypervisorVO.class, "hypervisorVersion", true, null, null);
List<GuestOSHypervisorVO> mappings = listBy(sc, filter);
for (GuestOSHypervisorVO mapping : mappings) {
versions.add(mapping.getHypervisorVersion());
}
return versions;
}
}

View File

@ -515,4 +515,7 @@ ALTER VIEW `cloud`.`image_store_view` AS
left join
`cloud`.`data_center` ON image_store.data_center_id = data_center.id
left join
`cloud`.`image_store_details` ON image_store_details.store_id = image_store.id;
`cloud`.`image_store_details` ON image_store_details.store_id = image_store.id;
-- OVF configured OS while registering deploy-as-is templates
INSERT IGNORE INTO `cloud`.`guest_os` (uuid, category_id, display_name, created) VALUES (UUID(), 11, 'OVF Configured OS', now());

View File

@ -23,6 +23,7 @@ import com.cloud.agent.api.to.DataStoreTO;
import com.cloud.agent.api.to.DataTO;
import com.cloud.agent.api.to.DiskTO;
import com.cloud.agent.api.to.NicTO;
import com.cloud.agent.api.to.OVFInformationTO;
import com.cloud.agent.api.to.deployasis.OVFConfigurationTO;
import com.cloud.agent.api.to.deployasis.OVFEulaSectionTO;
import com.cloud.agent.api.to.deployasis.OVFPropertyTO;
@ -34,11 +35,24 @@ import com.cloud.deployasis.TemplateDeployAsIsDetailVO;
import com.cloud.deployasis.UserVmDeployAsIsDetailVO;
import com.cloud.deployasis.dao.TemplateDeployAsIsDetailsDao;
import com.cloud.deployasis.dao.UserVmDeployAsIsDetailsDao;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.storage.GuestOSCategoryVO;
import com.cloud.storage.GuestOSHypervisorVO;
import com.cloud.storage.GuestOSVO;
import com.cloud.storage.VMTemplateStoragePoolVO;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.Volume;
import com.cloud.storage.dao.GuestOSCategoryDao;
import com.cloud.storage.dao.GuestOSDao;
import com.cloud.storage.dao.GuestOSHypervisorDao;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VMTemplatePoolDao;
import com.cloud.utils.Pair;
import com.cloud.utils.compression.CompressionUtil;
import com.cloud.utils.crypt.DBEncryptionUtil;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallbackNoReturn;
import com.cloud.utils.db.TransactionStatus;
import com.cloud.vm.VirtualMachineProfile;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@ -47,14 +61,18 @@ import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import javax.inject.Inject;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Component
public class DeployAsIsHelperImpl implements DeployAsIsHelper {
@ -70,6 +88,14 @@ public class DeployAsIsHelperImpl implements DeployAsIsHelper {
private PrimaryDataStoreDao storagePoolDao;
@Inject
private VMTemplatePoolDao templateStoragePoolDao;
@Inject
private VMTemplateDao templateDao;
@Inject
private GuestOSDao guestOSDao;
@Inject
private GuestOSHypervisorDao guestOSHypervisorDao;
@Inject
private GuestOSCategoryDao guestOSCategoryDao;
static {
GsonBuilder builder = new GsonBuilder();
@ -78,30 +104,180 @@ public class DeployAsIsHelperImpl implements DeployAsIsHelper {
}
public void persistTemplateDeployAsIsDetails(long templateId, DownloadAnswer answer) {
List<OVFPropertyTO> ovfProperties = answer.getOvfProperties();
List<OVFNetworkTO> networkRequirements = answer.getNetworkRequirements();
OVFVirtualHardwareSectionTO ovfHardwareSection = answer.getOvfHardwareSection();
List<OVFEulaSectionTO> eulaSections = answer.getEulaSections();
OVFInformationTO ovfInformationTO = answer.getOvfInformationTO();
if (ovfInformationTO != null) {
List<OVFPropertyTO> ovfProperties = ovfInformationTO.getProperties();
List<OVFNetworkTO> networkRequirements = ovfInformationTO.getNetworks();
OVFVirtualHardwareSectionTO ovfHardwareSection = ovfInformationTO.getHardwareSection();
List<OVFEulaSectionTO> eulaSections = ovfInformationTO.getEulaSections();
Pair<String, String> guestOsInfo = ovfInformationTO.getGuestOsInfo();
if (CollectionUtils.isNotEmpty(ovfProperties)) {
persistTemplateDeployAsIsInformationTOList(templateId, ovfProperties);
}
if (CollectionUtils.isNotEmpty(networkRequirements)) {
persistTemplateDeployAsIsInformationTOList(templateId, networkRequirements);
}
if (CollectionUtils.isNotEmpty(eulaSections)) {
persistTemplateDeployAsIsInformationTOList(templateId, eulaSections);
}
if (ovfHardwareSection != null) {
if (CollectionUtils.isNotEmpty(ovfHardwareSection.getConfigurations())) {
persistTemplateDeployAsIsInformationTOList(templateId, ovfHardwareSection.getConfigurations());
if (CollectionUtils.isNotEmpty(ovfProperties)) {
persistTemplateDeployAsIsInformationTOList(templateId, ovfProperties);
}
if (CollectionUtils.isNotEmpty(ovfHardwareSection.getCommonHardwareItems())) {
persistTemplateDeployAsIsInformationTOList(templateId, ovfHardwareSection.getCommonHardwareItems());
if (CollectionUtils.isNotEmpty(networkRequirements)) {
persistTemplateDeployAsIsInformationTOList(templateId, networkRequirements);
}
if (CollectionUtils.isNotEmpty(eulaSections)) {
persistTemplateDeployAsIsInformationTOList(templateId, eulaSections);
}
String minimumHardwareVersion = null;
if (ovfHardwareSection != null) {
if (CollectionUtils.isNotEmpty(ovfHardwareSection.getConfigurations())) {
persistTemplateDeployAsIsInformationTOList(templateId, ovfHardwareSection.getConfigurations());
}
if (CollectionUtils.isNotEmpty(ovfHardwareSection.getCommonHardwareItems())) {
persistTemplateDeployAsIsInformationTOList(templateId, ovfHardwareSection.getCommonHardwareItems());
}
minimumHardwareVersion = ovfHardwareSection.getMinimiumHardwareVersion();
}
if (guestOsInfo != null) {
String osType = guestOsInfo.first();
String osDescription = guestOsInfo.second();
LOGGER.info("Guest OS information retrieved from the template: " + osType + " - " + osDescription);
try {
handleGuestOsFromOVFDescriptor(templateId, osType, osDescription, minimumHardwareVersion);
} catch (Exception e) {
LOGGER.error("Error handling the guest OS read from the OVF " + osType, e);
}
}
}
}
/**
* Handle the guest OS read from the OVF and try to match it to an existing guest OS in DB.
* If the guest OS cannot be mapped to an existing guest OS in DB, then create it and create support for hypervisor versions.
* Roll back actions in case of unexpected erros
*/
private void handleGuestOsFromOVFDescriptor(long templateId, String guestOsType, String guestOsDescription,
String minimumHardwareVersion) {
VMTemplateVO template = templateDao.findById(templateId);
Hypervisor.HypervisorType hypervisor = template.getHypervisorType();
if (hypervisor != Hypervisor.HypervisorType.VMware) {
return;
}
String minimumHypervisorVersion = getMinimumSupportedHypervisorVersionForHardwareVersion(minimumHardwareVersion);
LOGGER.info("Minimum hardware version " + minimumHardwareVersion + " matched to hypervisor version " + minimumHypervisorVersion + ". " +
"Checking guest OS supporting this version");
List<GuestOSHypervisorVO> guestOsMappings = guestOSHypervisorDao.listByOsNameAndHypervisorMinimumVersion(guestOsType,
hypervisor.toString(), minimumHypervisorVersion);
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
if (CollectionUtils.isNotEmpty(guestOsMappings)) {
Pair<Boolean, Set<String>> result = updateDeployAsIsTemplateToExistingGuestOs(template, guestOsMappings, guestOsDescription);
if (!result.first()) {
// If couldnt find a guest OS matching the display name, create a new guest OS
updateDeployAsIsTemplateToNewGuestOs(template, guestOsType, guestOsDescription, hypervisor, result.second());
}
} else {
// The guest OS is not present in DB, create a new guest OS entry and mappings for supported versions
List<String> hypervisorVersions = guestOSHypervisorDao.listHypervisorSupportedVersionsFromMinimumVersion(
hypervisor.toString(), minimumHypervisorVersion);
updateDeployAsIsTemplateToNewGuestOs(template, guestOsType, guestOsDescription, hypervisor, hypervisorVersions);
}
}
});
}
/**
* Return true if the template guest OS can be updated to an existing guest OS matching the display name to
* the guest OS description from the OVF. (the second element of the returned pair is not used)
* If the guest OS does not exist, return false and the hypervisor versions that the guest OS must support
*/
private Pair<Boolean, Set<String>> updateDeployAsIsTemplateToExistingGuestOs(VMTemplateVO template,
List<GuestOSHypervisorVO> guestOsMappings,
String guestOsDescription) {
Set<String> versionsToSupport = new HashSet<>();
for (GuestOSHypervisorVO mapping : guestOsMappings) {
long guestOsId = mapping.getGuestOsId();
GuestOSVO guestOs = guestOSDao.findById(guestOsId);
versionsToSupport.add(mapping.getHypervisorVersion());
if (guestOs.getDisplayName().equalsIgnoreCase(guestOsDescription)) {
LOGGER.info("Found guest OS mapping for OVF read guest OS " + guestOsDescription +
" to hypervisor version " + mapping.getHypervisorVersion());
LOGGER.info("Updating deploy-as-is template guest OS to " + guestOs.getDisplayName());
updateTemplateGuestOsId(template, guestOsId);
return new Pair<>(true, versionsToSupport);
}
}
LOGGER.info("Could not map the OVF read guest OS " + guestOsDescription + " to an existing guest OS");
return new Pair<>(false, versionsToSupport);
}
/**
* Updates the deploy-as-is template guest OS doing:
* - Create a new guest OS with the guest OS description parsed from the OVF
* - Create mappings for the new guest OS and supported hypervisor versions
* - Update the template guest OS ID to the new guest OS ID
*/
private void updateDeployAsIsTemplateToNewGuestOs(VMTemplateVO template, String guestOsType, String guestOsDescription,
Hypervisor.HypervisorType hypervisor, Collection<String> hypervisorVersions) {
GuestOSVO newGuestOs = createGuestOsEntry(guestOsDescription);
for (String hypervisorVersion : hypervisorVersions) {
LOGGER.info(String.format("Adding a new guest OS mapping for hypervisor: %s version: %s and " +
"guest OS: %s", hypervisor.toString(), hypervisorVersion, guestOsType));
createGuestOsHypervisorMapping(newGuestOs.getId(), guestOsType, hypervisor.toString(), hypervisorVersion);
}
updateTemplateGuestOsId(template, newGuestOs.getId());
}
private void updateTemplateGuestOsId(VMTemplateVO template, long guestOsId) {
template.setGuestOSId(guestOsId);
templateDao.update(template.getId(), template);
}
/**
* Create a new entry on guest_os_hypervisor
*/
private void createGuestOsHypervisorMapping(long guestOsId, String guestOsType, String hypervisorType, String hypervisorVersion) {
GuestOSHypervisorVO mappingVO = new GuestOSHypervisorVO();
mappingVO.setGuestOsId(guestOsId);
mappingVO.setHypervisorType(hypervisorType);
mappingVO.setHypervisorVersion(hypervisorVersion);
mappingVO.setGuestOsName(guestOsType);
guestOSHypervisorDao.persist(mappingVO);
}
/**
* Create new guest OS entry with category 'Other'
*/
private GuestOSVO createGuestOsEntry(String guestOsDescription) {
GuestOSCategoryVO categoryVO = guestOSCategoryDao.findByCategoryName("Other");
long categoryId = categoryVO != null ? categoryVO.getId() : 7L;
GuestOSVO guestOSVO = new GuestOSVO();
guestOSVO.setDisplayName(guestOsDescription);
guestOSVO.setCategoryId(categoryId);
return guestOSDao.persist(guestOSVO);
}
/**
* Minimum VMware hosts supported version is 6.0
*/
protected String getMinimumSupportedHypervisorVersionForHardwareVersion(String hardwareVersion) {
// From https://kb.vmware.com/s/article/1003746 and https://kb.vmware.com/s/article/2007240
String hypervisorVersion = "default";
if (StringUtils.isBlank(hardwareVersion)) {
return hypervisorVersion;
}
String hwVersion = hardwareVersion.replace("vmx-", "");
try {
int hwVersionNumber = Integer.parseInt(hwVersion);
if (hwVersionNumber <= 11) {
hypervisorVersion = "6.0";
} else if (hwVersionNumber == 13) {
hypervisorVersion = "6.5";
} else if (hwVersionNumber >= 14) {
hypervisorVersion = "6.7";
}
} catch (NumberFormatException e) {
LOGGER.error("Cannot parse hardware version " + hwVersion + " to integer. Using default hypervisor version", e);
}
return hypervisorVersion;
}
@Override
public Map<String, String> getVirtualMachineDeployAsIsProperties(VirtualMachineProfile vm) {
Map<String, String> map = new HashMap<>();

View File

@ -23,6 +23,7 @@ import java.util.Map;
import javax.inject.Inject;
import com.cloud.deployasis.DeployAsIsConstants;
import com.cloud.storage.upload.params.IsoUploadParams;
import com.cloud.storage.upload.params.TemplateUploadParams;
import com.cloud.storage.upload.params.UploadParams;
@ -167,6 +168,13 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
if (requiresHVM == null) {
requiresHVM = true;
}
if (deployAsIs) {
GuestOS deployAsIsGuestOs = ApiDBUtils.findGuestOSByDisplayName(DeployAsIsConstants.DEFAULT_GUEST_OS_DEPLOY_AS_IS);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Setting default guest OS for deploy-as-is template while the template registration is not completed");
}
guestOSId = deployAsIsGuestOs.getId();
}
}
if (isExtractable == null) {

View File

@ -37,10 +37,7 @@ import java.util.concurrent.Executors;
import javax.naming.ConfigurationException;
import com.cloud.agent.api.to.deployasis.OVFEulaSectionTO;
import com.cloud.agent.api.to.deployasis.OVFVirtualHardwareSectionTO;
import com.cloud.agent.api.to.DatadiskTO;
import com.cloud.agent.api.to.deployasis.OVFPropertyTO;
import com.cloud.agent.api.to.OVFInformationTO;
import com.cloud.storage.template.Processor;
import com.cloud.storage.template.S3TemplateDownloader;
import com.cloud.storage.template.TemplateDownloader;
@ -58,7 +55,6 @@ import com.cloud.storage.template.RawImageProcessor;
import com.cloud.storage.template.TARProcessor;
import com.cloud.storage.template.VhdProcessor;
import com.cloud.storage.template.TemplateConstants;
import com.cloud.agent.api.to.deployasis.OVFNetworkTO;
import org.apache.cloudstack.storage.command.DownloadCommand;
import org.apache.cloudstack.storage.command.DownloadCommand.ResourceType;
import org.apache.cloudstack.storage.command.DownloadProgressCommand;
@ -66,7 +62,6 @@ import org.apache.cloudstack.storage.command.DownloadProgressCommand.RequestType
import org.apache.cloudstack.storage.NfsMountManagerImpl.PathParser;
import org.apache.cloudstack.storage.resource.NfsSecondaryStorageResource;
import org.apache.cloudstack.storage.resource.SecondaryStorageResource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
import com.cloud.agent.api.storage.DownloadAnswer;
@ -131,11 +126,7 @@ public class DownloadManagerImpl extends ManagerBase implements DownloadManager
private long templatePhysicalSize;
private final long id;
private final ResourceType resourceType;
private List<OVFPropertyTO> ovfProperties;
private List<OVFNetworkTO> networks;
private List<DatadiskTO> disks;
private OVFVirtualHardwareSectionTO hardwareSection;
private List<OVFEulaSectionTO> eulaSections;
private OVFInformationTO ovfInformationTO;
public DownloadJob(TemplateDownloader td, String jobId, long id, String tmpltName, ImageFormat format, boolean hvm, Long accountId, String descr, String cksum,
String installPathPrefix, ResourceType resourceType) {
@ -231,44 +222,12 @@ public class DownloadManagerImpl extends ManagerBase implements DownloadManager
this.checksum = checksum;
}
public List<OVFPropertyTO> getOvfProperties() {
return ovfProperties;
public OVFInformationTO getOvfInformationTO() {
return ovfInformationTO;
}
public void setOvfProperties(List<OVFPropertyTO> ovfProperties) {
this.ovfProperties = ovfProperties;
}
public List<OVFNetworkTO> getNetworks() {
return networks;
}
public void setNetworks(List<OVFNetworkTO> networks) {
this.networks = networks;
}
public List<DatadiskTO> getDisks() {
return disks;
}
public void setDisks(List<DatadiskTO> disks) {
this.disks = disks;
}
public void setVirtualHardwareSection(OVFVirtualHardwareSectionTO section) {
this.hardwareSection = section;
}
public OVFVirtualHardwareSectionTO getVirtualHardwareSection() {
return this.hardwareSection;
}
public List<OVFEulaSectionTO> getEulaSections() {
return eulaSections;
}
public void setEulaSections(List<OVFEulaSectionTO> eulaSections) {
this.eulaSections = eulaSections;
public void setOvfInformationTO(OVFInformationTO ovfInformationTO) {
this.ovfInformationTO = ovfInformationTO;
}
}
@ -563,18 +522,8 @@ public class DownloadManagerImpl extends ManagerBase implements DownloadManager
}
dnld.setTemplatesize(info.virtualSize);
dnld.setTemplatePhysicalSize(info.size);
if (CollectionUtils.isNotEmpty(info.ovfProperties)) {
dnld.setOvfProperties(info.ovfProperties);
}
if (CollectionUtils.isNotEmpty(info.networks)) {
dnld.setNetworks(info.networks);
}
if (CollectionUtils.isNotEmpty(info.disks)) {
dnld.setDisks(info.disks);
}
dnld.setVirtualHardwareSection(info.hardwareSection);
if (CollectionUtils.isNotEmpty(info.eulaSections)) {
dnld.setEulaSections(info.eulaSections);
if (info.ovfInformationTO != null) {
dnld.setOvfInformationTO(info.ovfInformationTO);
}
break;
}
@ -876,18 +825,8 @@ public class DownloadManagerImpl extends ManagerBase implements DownloadManager
answer =
new DownloadAnswer(jobId, getDownloadPct(jobId), getDownloadError(jobId), getDownloadStatus2(jobId), getDownloadLocalPath(jobId),
getInstallPath(jobId), getDownloadTemplateSize(jobId), getDownloadTemplatePhysicalSize(jobId), getDownloadCheckSum(jobId));
if (CollectionUtils.isNotEmpty(dj.getOvfProperties())) {
answer.setOvfProperties(dj.getOvfProperties());
}
if (CollectionUtils.isNotEmpty(dj.getNetworks())) {
answer.setNetworkRequirements(dj.getNetworks());
}
if (CollectionUtils.isNotEmpty(dj.getDisks())) {
answer.setDisks(dj.getDisks());
}
answer.setOvfHardwareSection(dj.getVirtualHardwareSection());
if (CollectionUtils.isNotEmpty(dj.getEulaSections())) {
answer.setEulaSections(dj.getEulaSections());
if (dj.getOvfInformationTO() != null) {
answer.setOvfInformationTO(dj.getOvfInformationTO());
}
jobs.remove(jobId);
return answer;