mirror of https://github.com/apache/cloudstack.git
fix for preserving nic mac and ip
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
This commit is contained in:
parent
e8cf62a0c4
commit
9ea3364b10
|
|
@ -92,6 +92,8 @@ public interface AccountService {
|
|||
|
||||
Account getAccount(long accountId);
|
||||
|
||||
Account getAccountByUuid(String accountUuid);
|
||||
|
||||
User getActiveUser(long userId);
|
||||
|
||||
User getOneActiveUserForAccount(Account account);
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ import org.apache.cloudstack.veeam.api.dto.VmAction;
|
|||
import org.apache.cloudstack.veeam.api.dto.VnicProfile;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
|
@ -192,6 +193,7 @@ import com.cloud.utils.exception.CloudRuntimeException;
|
|||
import com.cloud.vm.NicVO;
|
||||
import com.cloud.vm.UserVmManager;
|
||||
import com.cloud.vm.UserVmVO;
|
||||
import com.cloud.vm.VMInstanceDetailVO;
|
||||
import com.cloud.vm.VmDetailConstants;
|
||||
import com.cloud.vm.dao.NicDao;
|
||||
import com.cloud.vm.dao.UserVmDao;
|
||||
|
|
@ -207,6 +209,7 @@ public class ServerAdapter extends ManagerBase {
|
|||
);
|
||||
private static final String VM_TA_KEY = "veeam_tag";
|
||||
private static final String WORKER_VM_GUEST_CPU_MODE = "host-passthrough";
|
||||
private static final String RESTORE_CONFIG = "restore.config";
|
||||
|
||||
@Inject
|
||||
AccountService accountService;
|
||||
|
|
@ -512,7 +515,7 @@ public class ServerAdapter extends ManagerBase {
|
|||
return template;
|
||||
}
|
||||
|
||||
protected Vm createInstance(com.cloud.dc.DataCenter zone, Long clusterId, Account owner, Long domainId,
|
||||
protected Pair<Vm, UserVm> createInstance(com.cloud.dc.DataCenter zone, Long clusterId, Account owner, Long domainId,
|
||||
String accountName, Long projectId, String name, String displayName, String serviceOfferingUuid,
|
||||
int cpu, int memory, String templateUuid, String userdata, ApiConstants.BootType bootType,
|
||||
ApiConstants.BootMode bootMode, String affinityGroupId, String userDataId, Map<String, String> details) {
|
||||
|
|
@ -582,8 +585,10 @@ public class ServerAdapter extends ManagerBase {
|
|||
UserVm vm = userVmManager.createVirtualMachine(cmd);
|
||||
vm = userVmManager.finalizeCreateVirtualMachine(vm.getId());
|
||||
UserVmJoinVO vo = userVmJoinDao.findById(vm.getId());
|
||||
return UserVmJoinVOToVmConverter.toVm(vo, this::getHostById, this::getDetailsByInstanceId,
|
||||
this::listTagsByInstanceId, this::listDiskAttachmentsByInstanceId, this::listNicsByInstance, false);
|
||||
Vm vmObj = UserVmJoinVOToVmConverter.toVm(vo, this::getHostById, this::getDetailsByInstanceId,
|
||||
this::listTagsByInstanceId, this::listDiskAttachmentsByInstanceId, this::listNicsByInstance,
|
||||
false);
|
||||
return new Pair<>(vmObj, vm);
|
||||
} catch (InsufficientCapacityException | ResourceUnavailableException | ResourceAllocationException | CloudRuntimeException e) {
|
||||
throw new CloudRuntimeException("Failed to create VM: " + e.getMessage(), e);
|
||||
}
|
||||
|
|
@ -618,6 +623,63 @@ public class ServerAdapter extends ManagerBase {
|
|||
return details;
|
||||
}
|
||||
|
||||
protected void saveInstanceRestoreConfig(Vm request, UserVm vm) {
|
||||
if (StringUtils.isBlank(request.getAccountId())) {
|
||||
return;
|
||||
}
|
||||
if (accountService.getAccountByUuid(request.getAccountId()) == null) {
|
||||
return;
|
||||
}
|
||||
String restoreConfig = OvfXmlUtil.getConfigMetadataXml(request, logger);
|
||||
if (StringUtils.isBlank(restoreConfig)) {
|
||||
return;
|
||||
}
|
||||
vmInstanceDetailsDao.addDetail(vm.getId(), RESTORE_CONFIG, restoreConfig, false);
|
||||
}
|
||||
|
||||
protected void removeInstanceRestoreConfig(UserVm vm) {
|
||||
vmInstanceDetailsDao.removeDetail(vm.getId(), RESTORE_CONFIG);
|
||||
}
|
||||
|
||||
protected Pair<String, String> getValidatedInstanceNicDetails(final UserVmVO vm, final NetworkVO network) {
|
||||
if (ObjectUtils.anyNull(vm, network)) {
|
||||
return new Pair<>(null, null);
|
||||
}
|
||||
VMInstanceDetailVO detail = vmInstanceDetailsDao.findDetail(vm.getId(), RESTORE_CONFIG);
|
||||
if (detail == null || StringUtils.isBlank(detail.getValue())) {
|
||||
return new Pair<>(null, null);
|
||||
}
|
||||
Pair<String, String> result = OvfXmlUtil.getVmNicDetailFromStoredConfig(detail.getValue(), network.getUuid(), logger);
|
||||
String mac = StringUtils.trimToNull(result.first());
|
||||
String ip4Address = StringUtils.trimToNull(result.second());
|
||||
NicVO nic = null;
|
||||
if (mac != null) {
|
||||
nic = nicDao.findByNetworkIdAndMacAddress(network.getId(), mac);
|
||||
if (nic != null) {
|
||||
logger.warn("MAC address {} specified in the restore config for {} is already in use by {}, ignoring it",
|
||||
mac, network, nic);
|
||||
mac = null;
|
||||
if (!Objects.equals(ip4Address, nic.getIPv4Address())) {
|
||||
nic = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ip4Address != null) {
|
||||
if (nic == null) {
|
||||
nic = nicDao.findNonPlaceHolderByIp4AddressAndNetworkId(ip4Address, network.getId());
|
||||
}
|
||||
if (nic != null) {
|
||||
logger.warn("IPv4 address {} specified in the restore config for {} is already in use by {}, ignoring it",
|
||||
ip4Address, network, nic);
|
||||
mac = null;
|
||||
if (Objects.equals(ip4Address, nic.getIPv4Address())) {
|
||||
ip4Address = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new Pair<>(mac, ip4Address);
|
||||
}
|
||||
|
||||
protected static long getProvisionedSizeInGb(String sizeStr) {
|
||||
long provisionedSizeInGb;
|
||||
try {
|
||||
|
|
@ -968,10 +1030,12 @@ public class ServerAdapter extends ManagerBase {
|
|||
if (request.getTemplate() != null && StringUtils.isNotEmpty(request.getTemplate().getId())) {
|
||||
templateUuid = request.getTemplate().getId();
|
||||
}
|
||||
return createInstance(zone, clusterId, owner, ownerDetails.first(), ownerDetails.second(),
|
||||
Pair<Vm, UserVm> result = createInstance(zone, clusterId, owner, ownerDetails.first(), ownerDetails.second(),
|
||||
ownerDetails.third(), name, displayName, serviceOfferingUuid, cpu, memoryMB, templateUuid,
|
||||
userdata, bootOptions.first(), bootOptions.second(), request.getAffinityGroupId(),
|
||||
request.getUserDataId(), request.getDetails());
|
||||
saveInstanceRestoreConfig(request, result.second());
|
||||
return result.first();
|
||||
}
|
||||
|
||||
@ApiAccess(command = UpdateVMCmd.class)
|
||||
|
|
@ -1175,6 +1239,7 @@ public class ServerAdapter extends ManagerBase {
|
|||
}
|
||||
accountService.checkAccess(CallContext.current().getCallingAccount(), SecurityChecker.AccessType.OperateEntry,
|
||||
false, vmVo);
|
||||
removeInstanceRestoreConfig(vmVo);
|
||||
if (vmVo.getAccountId() != volumeVO.getAccountId()) {
|
||||
if (VeeamControlService.InstanceRestoreAssignOwner.value()) {
|
||||
assignVolumeToAccount(volumeVO, vmVo.getAccountId());
|
||||
|
|
@ -1296,10 +1361,13 @@ public class ServerAdapter extends ManagerBase {
|
|||
accountCannotAccessNetwork(networkVO, vmVo.getAccountId())) {
|
||||
assignVmToAccount(vmVo, networkVO.getAccountId());
|
||||
}
|
||||
Pair<String, String> nicDetails = getValidatedInstanceNicDetails(vmVo, networkVO);
|
||||
AddNicToVMCmd cmd = new AddNicToVMCmd();
|
||||
ComponentContext.inject(cmd);
|
||||
cmd.setVmId(vmVo.getId());
|
||||
cmd.setNetworkId(networkVO.getId());
|
||||
cmd.setMacAddress(nicDetails.first());
|
||||
cmd.setIpaddr(nicDetails.second());
|
||||
if (request.getMac() != null && StringUtils.isNotBlank(request.getMac().getAddress())) {
|
||||
cmd.setMacAddress(request.getMac().getAddress());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package org.apache.cloudstack.veeam.api.converter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
|
@ -79,23 +80,34 @@ public class NicVOToNicConverter {
|
|||
device.setDescription(String.format("%s device", vo.getReserver()));
|
||||
device.setMac(mac);
|
||||
if (ObjectUtils.anyNotNull(vo.getIPv4Address(), vo.getIPv6Address())) {
|
||||
Ip ip = new Ip();
|
||||
if (vo.getIPv4Address() != null) {
|
||||
ip.setAddress(vo.getIPv4Address());
|
||||
ip.setGateway(vo.getIPv4Gateway());
|
||||
ip.setVersion("v4");
|
||||
} else if (vo.getIPv6Address() != null) {
|
||||
ip.setAddress(vo.getIPv6Address());
|
||||
ip.setGateway(vo.getIPv6Gateway());
|
||||
ip.setVersion("v6");
|
||||
}
|
||||
device.setIps(NamedList.of("ip", List.of(ip)));
|
||||
List<Ip> ips = getIps(vo);
|
||||
device.setIps(NamedList.of("ip", ips));
|
||||
}
|
||||
device.setHref(vm.getHref() + "/reporteddevices/" + vo.getUuid());
|
||||
device.setVm(vm);
|
||||
return device;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<Ip> getIps(NicVO vo) {
|
||||
List<Ip> ips = new ArrayList<>();
|
||||
if (vo.getIPv4Address() != null) {
|
||||
Ip ip = new Ip();
|
||||
ip.setAddress(vo.getIPv4Address());
|
||||
ip.setGateway(vo.getIPv4Gateway());
|
||||
ip.setVersion("v4");
|
||||
ips.add(ip);
|
||||
}
|
||||
if (vo.getIPv6Address() != null) {
|
||||
Ip ip6 = new Ip();
|
||||
ip6.setAddress(vo.getIPv6Address());
|
||||
ip6.setGateway(vo.getIPv6Gateway());
|
||||
ip6.setVersion("v6");
|
||||
ips.add(ip6);
|
||||
}
|
||||
return ips;
|
||||
}
|
||||
|
||||
public static List<Nic> toNicList(final List<NicVO> vos, final String vmUuid, final Function<Long, NetworkVO> networkResolver) {
|
||||
return vos.stream()
|
||||
.map(vo -> toNic(vo, vmUuid, networkResolver))
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
package org.apache.cloudstack.veeam.api.dto;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
|
@ -32,6 +33,7 @@ import javax.xml.XMLConstants;
|
|||
import javax.xml.namespace.NamespaceContext;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
|
|
@ -41,11 +43,15 @@ import org.apache.commons.collections.CollectionUtils;
|
|||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.cloud.api.query.vo.UserVmJoinVO;
|
||||
import com.cloud.utils.Pair;
|
||||
|
||||
public class OvfXmlUtil {
|
||||
|
||||
|
|
@ -108,8 +114,8 @@ public class OvfXmlUtil {
|
|||
final String bootTime = vm.getStartTime() != null ? formatDate(vm.getStartTime()) : creationDate;
|
||||
|
||||
// Memory: Vm.memory is bytes (string)
|
||||
final long memBytes = parseLong(vm.getMemory(), 1024L * 1024L * 1024L);
|
||||
final long memMb = Math.max(128, memBytes / (1024L * 1024L));
|
||||
final long memBytes = parseLong(vm.getMemory(), MemoryAllocationUnit.Gigabytes.getBytesMultiplier());
|
||||
final long memMb = Math.max(128, memBytes / MemoryAllocationUnit.Megabytes.getBytesMultiplier());
|
||||
|
||||
// CPU: topology cores/sockets/threads. We default sockets=1 threads=1.
|
||||
final int vcpu = Math.max(1, Integer.parseInt(vm.getCpu().getTopology().getCores()));
|
||||
|
|
@ -126,6 +132,8 @@ public class OvfXmlUtil {
|
|||
// Snapshot id (stable per VM id)
|
||||
final String snapshotId = UUID.nameUUIDFromBytes(("ovf-snap-" + vmId).getBytes(StandardCharsets.UTF_8)).toString();
|
||||
|
||||
final List<Nic> nics = nics(vm);
|
||||
|
||||
final StringBuilder sb = new StringBuilder(16_384);
|
||||
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
sb.append("<ovf:Envelope ");
|
||||
|
|
@ -174,7 +182,7 @@ public class OvfXmlUtil {
|
|||
if (da == null || da.getDisk() == null || StringUtils.isBlank(da.getDisk().getId())) {
|
||||
continue;
|
||||
}
|
||||
final org.apache.cloudstack.veeam.api.dto.Disk d = da.getDisk();
|
||||
final Disk d = da.getDisk();
|
||||
final String diskId = d.getId();
|
||||
final String storageDomainId = firstStorageDomainId(d);
|
||||
final String href = storageDomainId + "/" + diskId;
|
||||
|
|
@ -247,6 +255,26 @@ public class OvfXmlUtil {
|
|||
if (vo.getAffinityGroupId() != null) {
|
||||
sb.append("<AffinityGroupId>").append(escapeText(vo.getAffinityGroupUuid())).append("</AffinityGroupId>");
|
||||
}
|
||||
if (vm.getNics() != null && CollectionUtils.isNotEmpty(vm.getNics().getItems())) {
|
||||
sb.append("<Nics>");
|
||||
for (Nic nic : nics(vm)) {
|
||||
if (nic == null || StringUtils.isBlank(nic.getId())) {
|
||||
continue;
|
||||
}
|
||||
String networkId = nicNetworkId(nic);
|
||||
if (networkId == null) {
|
||||
continue;
|
||||
}
|
||||
sb.append("<Nic>");
|
||||
sb.append("<Id>").append(escapeText(nic.getId())).append("</Id>");
|
||||
sb.append("<NetworkId>").append(escapeText(networkId)).append("</NetworkId>");
|
||||
sb.append("<MACAddress>").append(escapeText(nicMac(nic))).append("</MACAddress>");
|
||||
sb.append("<Ip4Address>").append(escapeText(nicIp(nic, "v4"))).append("</Ip4Address>");
|
||||
sb.append("<Ip6Address>").append(escapeText(nicIp(nic, "v6"))).append("</Ip6Address>");
|
||||
sb.append("</Nic>");
|
||||
}
|
||||
sb.append("</Nics>");
|
||||
}
|
||||
sb.append("</CloudStack>");
|
||||
sb.append("</Section>");
|
||||
}
|
||||
|
|
@ -349,7 +377,7 @@ public class OvfXmlUtil {
|
|||
if (da == null || da.getDisk() == null || StringUtils.isBlank(da.getDisk().getId())) {
|
||||
continue;
|
||||
}
|
||||
final org.apache.cloudstack.veeam.api.dto.Disk d = da.getDisk();
|
||||
final Disk d = da.getDisk();
|
||||
final String diskId = d.getId();
|
||||
final String storageDomainId = firstStorageDomainId(d);
|
||||
final String href = storageDomainId + "/" + diskId;
|
||||
|
|
@ -380,16 +408,17 @@ public class OvfXmlUtil {
|
|||
|
||||
// NICs as Items
|
||||
int nicSlot = 0;
|
||||
for (Nic nic : nics(vm)) {
|
||||
for (Nic nic : nics) {
|
||||
if (nic == null) {
|
||||
continue;
|
||||
}
|
||||
final String nicId = firstNonBlank(nic.getId(), UUID.nameUUIDFromBytes(("nic-" + vmId + "-" + nicSlot).getBytes(StandardCharsets.UTF_8)).toString());
|
||||
final String nicName = firstNonBlank(nic.getName(), "nic" + (nicSlot + 1));
|
||||
final String mac = nic.getMac() != null ? defaultString(nic.getMac().getAddress()) : "";
|
||||
final String elementName = nic.getVnicProfile() != null ? defaultString(nic.getVnicProfile().getId()) : nicName;
|
||||
|
||||
sb.append("<Item>");
|
||||
sb.append("<rasd:Caption>Ethernet adapter on [No Network]</rasd:Caption>");
|
||||
sb.append("<rasd:Caption>Ethernet adapter - ").append(nic.getName()).append("</rasd:Caption>");
|
||||
sb.append("<rasd:InstanceId>").append(escapeText(nicId)).append("</rasd:InstanceId>");
|
||||
sb.append("<rasd:ResourceType>10</rasd:ResourceType>");
|
||||
sb.append("<rasd:OtherResourceType></rasd:OtherResourceType>");
|
||||
|
|
@ -397,7 +426,7 @@ public class OvfXmlUtil {
|
|||
sb.append("<rasd:Connection>").append(escapeText(defaultString(inferNetworkName(nic)))).append("</rasd:Connection>");
|
||||
sb.append("<rasd:Linked>").append(escapeText(booleanString(nic.getLinked(), "true"))).append("</rasd:Linked>");
|
||||
sb.append("<rasd:Name>").append(escapeText(nicName)).append("</rasd:Name>");
|
||||
sb.append("<rasd:ElementName>").append(escapeText(nicName)).append("</rasd:ElementName>");
|
||||
sb.append("<rasd:ElementName>").append(escapeText(elementName)).append("</rasd:ElementName>");
|
||||
sb.append("<rasd:MACAddress>").append(escapeText(mac)).append("</rasd:MACAddress>");
|
||||
sb.append("<rasd:speed>10000</rasd:speed>");
|
||||
sb.append("<Type>interface</Type>");
|
||||
|
|
@ -441,16 +470,153 @@ public class OvfXmlUtil {
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void updateFromConfiguration(Vm vm) {
|
||||
protected static String getVmConfigurationData(Vm vm) {
|
||||
Vm.Initialization initialization = vm.getInitialization();
|
||||
if (initialization == null) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
Vm.Initialization.Configuration configuration = vm.getInitialization().getConfiguration();
|
||||
if (configuration == null) {
|
||||
return null;
|
||||
}
|
||||
return configuration.getData();
|
||||
}
|
||||
|
||||
public static void updateFromConfiguration(Vm vm) {
|
||||
String configurationData = getVmConfigurationData(vm);
|
||||
OvfXmlUtil.updateFromXml(vm, configurationData);
|
||||
}
|
||||
|
||||
public static String getConfigMetadataXml(Vm vm, Logger logger) {
|
||||
String configurationData = getVmConfigurationData(vm);
|
||||
if (StringUtils.isBlank(configurationData)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
dbf.setNamespaceAware(true);
|
||||
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
||||
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||
Document doc = db.parse(new ByteArrayInputStream(configurationData.getBytes(StandardCharsets.UTF_8)));
|
||||
|
||||
XPathFactory xpf = XPathFactory.newInstance();
|
||||
XPath xpath = xpf.newXPath();
|
||||
|
||||
// Persist only the CloudStack metadata section from the source OVF.
|
||||
Node metadataSection = (Node) xpath.evaluate(
|
||||
"//*[local-name()='Section' and @*[local-name()='type']='ovf:CloudStackMetadata_Type']",
|
||||
doc,
|
||||
XPathConstants.NODE
|
||||
);
|
||||
|
||||
if (metadataSection == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Wrap section payload so it remains standalone XML with namespace declarations.
|
||||
StringBuilder sb = new StringBuilder(2048);
|
||||
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
sb.append("<Sections")
|
||||
.append(" xmlns:rasd=\"").append(NS_RASD).append("\"")
|
||||
.append(" xmlns:ovf=\"").append(NS_OVF).append("\"")
|
||||
.append(" xmlns:xsi=\"").append(NS_XSI).append("\"")
|
||||
.append(">");
|
||||
sb.append(nodeToString(metadataSection));
|
||||
sb.append("</Sections>");
|
||||
|
||||
return sb.toString();
|
||||
} catch (ParserConfigurationException | XPathExpressionException | IOException | SAXException e) {
|
||||
logger.error("Failed to parse VM configuration data for VM id {}: {}", vm.getId(), e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Pair<String, String> getVmNicDetailFromStoredConfig(String xmlConfig, String networkId, Logger logger) {
|
||||
if (StringUtils.isAnyBlank(xmlConfig, networkId)) {
|
||||
return new Pair<>(null, null);
|
||||
}
|
||||
try {
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
dbf.setNamespaceAware(true);
|
||||
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
||||
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||
Document doc = db.parse(new ByteArrayInputStream(xmlConfig.getBytes(StandardCharsets.UTF_8)));
|
||||
|
||||
XPathFactory xpf = XPathFactory.newInstance();
|
||||
XPath xpath = xpf.newXPath();
|
||||
|
||||
// Preferred format: CloudStack metadata section with CloudStack/Nics/Nic records.
|
||||
NodeList nicNodes = (NodeList) xpath.evaluate(
|
||||
"//*[local-name()='Section' and @*[local-name()='type']='ovf:CloudStackMetadata_Type']/*[local-name()='CloudStack']/*[local-name()='Nics']/*[local-name()='Nic']",
|
||||
doc,
|
||||
XPathConstants.NODESET
|
||||
);
|
||||
if (nicNodes != null && nicNodes.getLength() > 0) {
|
||||
for (int i = 0; i < nicNodes.getLength(); i++) {
|
||||
Node nicNode = nicNodes.item(i);
|
||||
String nicNetworkId = xpathString(xpath, nicNode, "./*[local-name()='NetworkId']/text()");
|
||||
if (StringUtils.equals(nicNetworkId, networkId)) {
|
||||
return new Pair<>(
|
||||
xpathString(xpath, nicNode, "./*[local-name()='MACAddress' or local-name()='MACAddress']/text()"),
|
||||
xpathString(xpath, nicNode, "./*[local-name()='Ip4Address' or local-name()='Ip4Address']/text()")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ParserConfigurationException | XPathExpressionException | IOException | SAXException e) {
|
||||
logger.error("Failed to parse VM configuration XML to retrieve details for NIC for network ID {}: {}",
|
||||
networkId, e.getMessage());
|
||||
}
|
||||
return new Pair<>(null, null);
|
||||
}
|
||||
|
||||
private static String nodeToString(Node node) {
|
||||
try {
|
||||
// Implementation using string manipulation
|
||||
StringBuilder sb = new StringBuilder();
|
||||
serializeNodeToString(node, sb);
|
||||
return sb.toString();
|
||||
} catch (Exception e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private static void serializeNodeToString(Node node, StringBuilder sb) {
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
OvfXmlUtil.updateFromXml(vm, configuration.getData());
|
||||
|
||||
short nodeType = node.getNodeType();
|
||||
switch (nodeType) {
|
||||
case Node.ELEMENT_NODE:
|
||||
sb.append("<").append(node.getNodeName());
|
||||
NamedNodeMap attrs = node.getAttributes();
|
||||
if (attrs != null) {
|
||||
for (int i = 0; i < attrs.getLength(); i++) {
|
||||
Node attr = attrs.item(i);
|
||||
sb.append(" ").append(attr.getNodeName()).append("=\"")
|
||||
.append(escapeAttr(attr.getNodeValue())).append("\"");
|
||||
}
|
||||
}
|
||||
sb.append(">");
|
||||
NodeList children = node.getChildNodes();
|
||||
for (int i = 0; i < children.getLength(); i++) {
|
||||
serializeNodeToString(children.item(i), sb);
|
||||
}
|
||||
sb.append("</").append(node.getNodeName()).append(">");
|
||||
break;
|
||||
case Node.TEXT_NODE:
|
||||
String text = node.getNodeValue();
|
||||
if (StringUtils.isNotBlank(text)) {
|
||||
sb.append(escapeText(text));
|
||||
}
|
||||
break;
|
||||
case Node.CDATA_SECTION_NODE:
|
||||
sb.append("<![CDATA[").append(node.getNodeValue()).append("]]>");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected static void updateFromXml(Vm vm, String ovfXml) {
|
||||
|
|
@ -663,6 +829,40 @@ public class OvfXmlUtil {
|
|||
return vm.getNics().getItems();
|
||||
}
|
||||
|
||||
private static String nicNetworkId(Nic nic) {
|
||||
if (nic == null || nic.getVnicProfile() == null || StringUtils.isEmpty(nic.getVnicProfile().getId())) {
|
||||
return null;
|
||||
}
|
||||
return nic.getVnicProfile().getId();
|
||||
}
|
||||
|
||||
private static ReportedDevice getNicReportedDevice(Nic nic) {
|
||||
if (nic == null || nic.getReportedDevices() == null || CollectionUtils.isEmpty(nic.getReportedDevices().getItems())) {
|
||||
return null;
|
||||
}
|
||||
return nic.getReportedDevices().getItems().get(0);
|
||||
}
|
||||
|
||||
private static String nicMac(Nic nic) {
|
||||
if (nic == null || nic.getMac() == null || StringUtils.isBlank(nic.getMac().getAddress())) {
|
||||
return "";
|
||||
}
|
||||
return nic.getMac().getAddress();
|
||||
}
|
||||
|
||||
private static String nicIp(Nic nic, String version) {
|
||||
ReportedDevice device = getNicReportedDevice(nic);
|
||||
if (device == null || device.getIps() == null || CollectionUtils.isEmpty(device.getIps().getItems())) {
|
||||
return "";
|
||||
}
|
||||
for (Ip ip : device.getIps().getItems()) {
|
||||
if (version.equalsIgnoreCase(ip.getVersion())) {
|
||||
return ip.getAddress();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String inferOsDescription(Vm vm) {
|
||||
if (vm.getOs() == null) {
|
||||
return "other";
|
||||
|
|
@ -740,7 +940,7 @@ public class OvfXmlUtil {
|
|||
if (vm.getMemoryPolicy() == null || vm.getMemoryPolicy().getBallooning() == null) {
|
||||
return "true";
|
||||
}
|
||||
return "true".equalsIgnoreCase(vm.getMemoryPolicy().getBallooning()) ? "true" : "false";
|
||||
return Boolean.toString("true".equalsIgnoreCase(vm.getMemoryPolicy().getBallooning()));
|
||||
}
|
||||
|
||||
private static int mapNicResourceSubType(String iface) {
|
||||
|
|
@ -795,7 +995,7 @@ public class OvfXmlUtil {
|
|||
if (bytes <= 0) {
|
||||
return 0;
|
||||
}
|
||||
final long gib = 1024L * 1024L * 1024L;
|
||||
final long gib = MemoryAllocationUnit.Gigabytes.getBytesMultiplier();
|
||||
return (bytes + gib - 1) / gib;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,14 +48,17 @@ import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
|||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||
import org.apache.cloudstack.veeam.api.dto.DataCenter;
|
||||
import org.apache.cloudstack.veeam.api.dto.Disk;
|
||||
import org.apache.cloudstack.veeam.api.dto.OvfXmlUtil;
|
||||
import org.apache.cloudstack.veeam.api.dto.Tag;
|
||||
import org.apache.cloudstack.veeam.api.dto.Vm;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
|
|
@ -96,10 +99,14 @@ import com.cloud.user.User;
|
|||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.Ternary;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.vm.NicVO;
|
||||
import com.cloud.vm.UserVmManager;
|
||||
import com.cloud.vm.VMInstanceDetailVO;
|
||||
import com.cloud.vm.UserVmVO;
|
||||
import com.cloud.vm.VmDetailConstants;
|
||||
import com.cloud.vm.dao.NicDao;
|
||||
import com.cloud.vm.dao.UserVmDao;
|
||||
import com.cloud.vm.dao.VMInstanceDetailsDao;
|
||||
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
|
|
@ -117,6 +124,7 @@ public class ServerAdapterTest {
|
|||
@Mock NetworkDao networkDao;
|
||||
@Mock UserVmDao userVmDao;
|
||||
@Mock UserVmJoinDao userVmJoinDao;
|
||||
@Mock VMInstanceDetailsDao vmInstanceDetailsDao;
|
||||
@Mock VolumeDao volumeDao;
|
||||
@Mock VolumeJoinDao volumeJoinDao;
|
||||
// kept minimal: only mocks used directly by tests
|
||||
|
|
@ -126,6 +134,7 @@ public class ServerAdapterTest {
|
|||
@Mock ServiceOfferingDao serviceOfferingDao;
|
||||
@Mock VMTemplateDao templateDao;
|
||||
@Mock UserVmManager userVmManager;
|
||||
@Mock NicDao nicDao;
|
||||
@Mock AsyncJobDao asyncJobDao;
|
||||
@Mock AsyncJobJoinDao asyncJobJoinDao;
|
||||
@Mock VMSnapshotDao vmSnapshotDao;
|
||||
|
|
@ -266,6 +275,185 @@ public class ServerAdapterTest {
|
|||
assertEquals("3000", result.get(VmDetailConstants.CPU_SPEED));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValidatedInstanceNicDetails_NullVm_ReturnsNullPair() {
|
||||
NetworkVO network = mock(NetworkVO.class);
|
||||
|
||||
Pair<String, String> result = serverAdapter.getValidatedInstanceNicDetails(null, network);
|
||||
|
||||
assertNull(result.first());
|
||||
assertNull(result.second());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValidatedInstanceNicDetails_NullNetwork_ReturnsNullPair() {
|
||||
UserVmVO vm = mock(UserVmVO.class);
|
||||
|
||||
Pair<String, String> result = serverAdapter.getValidatedInstanceNicDetails(vm, null);
|
||||
|
||||
assertNull(result.first());
|
||||
assertNull(result.second());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValidatedInstanceNicDetails_NoRestoreConfig_ReturnsNullPair() {
|
||||
UserVmVO vm = mock(UserVmVO.class);
|
||||
when(vm.getId()).thenReturn(10L);
|
||||
when(vmInstanceDetailsDao.findDetail(10L, "restore.config")).thenReturn(null);
|
||||
NetworkVO network = mock(NetworkVO.class);
|
||||
|
||||
Pair<String, String> result = serverAdapter.getValidatedInstanceNicDetails(vm, network);
|
||||
|
||||
assertNull(result.first());
|
||||
assertNull(result.second());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValidatedInstanceNicDetails_BlankRestoreConfig_ReturnsNullPair() {
|
||||
UserVmVO vm = mock(UserVmVO.class);
|
||||
when(vm.getId()).thenReturn(10L);
|
||||
VMInstanceDetailVO detail = mock(VMInstanceDetailVO.class);
|
||||
when(detail.getValue()).thenReturn(" ");
|
||||
when(vmInstanceDetailsDao.findDetail(10L, "restore.config")).thenReturn(detail);
|
||||
NetworkVO network = mock(NetworkVO.class);
|
||||
|
||||
Pair<String, String> result = serverAdapter.getValidatedInstanceNicDetails(vm, network);
|
||||
|
||||
assertNull(result.first());
|
||||
assertNull(result.second());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValidatedInstanceNicDetails_BlankMacAndIpFromConfig_ReturnsNullPair() {
|
||||
UserVmVO vm = mock(UserVmVO.class);
|
||||
when(vm.getId()).thenReturn(11L);
|
||||
VMInstanceDetailVO detail = mock(VMInstanceDetailVO.class);
|
||||
when(detail.getValue()).thenReturn("restore-xml");
|
||||
when(vmInstanceDetailsDao.findDetail(11L, "restore.config")).thenReturn(detail);
|
||||
|
||||
NetworkVO network = mock(NetworkVO.class);
|
||||
when(network.getUuid()).thenReturn("network-uuid");
|
||||
|
||||
try (MockedStatic<OvfXmlUtil> ovfXmlUtil = Mockito.mockStatic(OvfXmlUtil.class)) {
|
||||
ovfXmlUtil.when(() -> OvfXmlUtil.getVmNicDetailFromStoredConfig(eq("restore-xml"), eq("network-uuid"), any(Logger.class)))
|
||||
.thenReturn(new Pair<>(" ", "\t"));
|
||||
|
||||
Pair<String, String> result = serverAdapter.getValidatedInstanceNicDetails(vm, network);
|
||||
|
||||
assertNull(result.first());
|
||||
assertNull(result.second());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValidatedInstanceNicDetails_NoConflicts_ReturnsMacAndIp() {
|
||||
UserVmVO vm = mock(UserVmVO.class);
|
||||
when(vm.getId()).thenReturn(20L);
|
||||
VMInstanceDetailVO detail = mock(VMInstanceDetailVO.class);
|
||||
when(detail.getValue()).thenReturn("restore-xml");
|
||||
when(vmInstanceDetailsDao.findDetail(20L, "restore.config")).thenReturn(detail);
|
||||
|
||||
NetworkVO network = mock(NetworkVO.class);
|
||||
when(network.getId()).thenReturn(30L);
|
||||
when(network.getUuid()).thenReturn("network-uuid");
|
||||
|
||||
when(nicDao.findByNetworkIdAndMacAddress(30L, "02:00:00:00:00:01")).thenReturn(null);
|
||||
when(nicDao.findNonPlaceHolderByIp4AddressAndNetworkId("10.0.0.10", 30L)).thenReturn(null);
|
||||
|
||||
try (MockedStatic<OvfXmlUtil> ovfXmlUtil = Mockito.mockStatic(OvfXmlUtil.class)) {
|
||||
ovfXmlUtil.when(() -> OvfXmlUtil.getVmNicDetailFromStoredConfig(eq("restore-xml"), eq("network-uuid"), any(Logger.class)))
|
||||
.thenReturn(new Pair<>("02:00:00:00:00:01", "10.0.0.10"));
|
||||
|
||||
Pair<String, String> result = serverAdapter.getValidatedInstanceNicDetails(vm, network);
|
||||
|
||||
assertEquals("02:00:00:00:00:01", result.first());
|
||||
assertEquals("10.0.0.10", result.second());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValidatedInstanceNicDetails_MacConflictWithSameIp_ClearsBoth() {
|
||||
UserVmVO vm = mock(UserVmVO.class);
|
||||
when(vm.getId()).thenReturn(21L);
|
||||
VMInstanceDetailVO detail = mock(VMInstanceDetailVO.class);
|
||||
when(detail.getValue()).thenReturn("restore-xml");
|
||||
when(vmInstanceDetailsDao.findDetail(21L, "restore.config")).thenReturn(detail);
|
||||
|
||||
NetworkVO network = mock(NetworkVO.class);
|
||||
when(network.getId()).thenReturn(31L);
|
||||
when(network.getUuid()).thenReturn("network-uuid");
|
||||
|
||||
NicVO conflictingNic = mock(NicVO.class);
|
||||
when(conflictingNic.getIPv4Address()).thenReturn("10.0.0.11");
|
||||
when(nicDao.findByNetworkIdAndMacAddress(31L, "02:00:00:00:00:02")).thenReturn(conflictingNic);
|
||||
|
||||
try (MockedStatic<OvfXmlUtil> ovfXmlUtil = Mockito.mockStatic(OvfXmlUtil.class)) {
|
||||
ovfXmlUtil.when(() -> OvfXmlUtil.getVmNicDetailFromStoredConfig(eq("restore-xml"), eq("network-uuid"), any(Logger.class)))
|
||||
.thenReturn(new Pair<>("02:00:00:00:00:02", "10.0.0.11"));
|
||||
|
||||
Pair<String, String> result = serverAdapter.getValidatedInstanceNicDetails(vm, network);
|
||||
|
||||
assertNull(result.first());
|
||||
assertNull(result.second());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValidatedInstanceNicDetails_MacConflictWithDifferentIp_ClearsOnlyMac() {
|
||||
UserVmVO vm = mock(UserVmVO.class);
|
||||
when(vm.getId()).thenReturn(22L);
|
||||
VMInstanceDetailVO detail = mock(VMInstanceDetailVO.class);
|
||||
when(detail.getValue()).thenReturn("restore-xml");
|
||||
when(vmInstanceDetailsDao.findDetail(22L, "restore.config")).thenReturn(detail);
|
||||
|
||||
NetworkVO network = mock(NetworkVO.class);
|
||||
when(network.getId()).thenReturn(32L);
|
||||
when(network.getUuid()).thenReturn("network-uuid");
|
||||
|
||||
NicVO conflictingNic = mock(NicVO.class);
|
||||
when(conflictingNic.getIPv4Address()).thenReturn("10.0.0.99");
|
||||
when(nicDao.findByNetworkIdAndMacAddress(32L, "02:00:00:00:00:03")).thenReturn(conflictingNic);
|
||||
when(nicDao.findNonPlaceHolderByIp4AddressAndNetworkId("10.0.0.12", 32L)).thenReturn(null);
|
||||
|
||||
try (MockedStatic<OvfXmlUtil> ovfXmlUtil = Mockito.mockStatic(OvfXmlUtil.class)) {
|
||||
ovfXmlUtil.when(() -> OvfXmlUtil.getVmNicDetailFromStoredConfig(eq("restore-xml"), eq("network-uuid"), any(Logger.class)))
|
||||
.thenReturn(new Pair<>("02:00:00:00:00:03", "10.0.0.12"));
|
||||
|
||||
Pair<String, String> result = serverAdapter.getValidatedInstanceNicDetails(vm, network);
|
||||
|
||||
assertNull(result.first());
|
||||
assertEquals("10.0.0.12", result.second());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValidatedInstanceNicDetails_IpConflict_ClearsIpAndMac() {
|
||||
UserVmVO vm = mock(UserVmVO.class);
|
||||
when(vm.getId()).thenReturn(23L);
|
||||
VMInstanceDetailVO detail = mock(VMInstanceDetailVO.class);
|
||||
when(detail.getValue()).thenReturn("restore-xml");
|
||||
when(vmInstanceDetailsDao.findDetail(23L, "restore.config")).thenReturn(detail);
|
||||
|
||||
NetworkVO network = mock(NetworkVO.class);
|
||||
when(network.getId()).thenReturn(33L);
|
||||
when(network.getUuid()).thenReturn("network-uuid");
|
||||
|
||||
when(nicDao.findByNetworkIdAndMacAddress(33L, "02:00:00:00:00:04")).thenReturn(null);
|
||||
NicVO conflictingIpNic = mock(NicVO.class);
|
||||
when(conflictingIpNic.getIPv4Address()).thenReturn("10.0.0.13");
|
||||
when(nicDao.findNonPlaceHolderByIp4AddressAndNetworkId("10.0.0.13", 33L)).thenReturn(conflictingIpNic);
|
||||
|
||||
try (MockedStatic<OvfXmlUtil> ovfXmlUtil = Mockito.mockStatic(OvfXmlUtil.class)) {
|
||||
ovfXmlUtil.when(() -> OvfXmlUtil.getVmNicDetailFromStoredConfig(eq("restore-xml"), eq("network-uuid"), any(Logger.class)))
|
||||
.thenReturn(new Pair<>("02:00:00:00:00:04", "10.0.0.13"));
|
||||
|
||||
Pair<String, String> result = serverAdapter.getValidatedInstanceNicDetails(vm, network);
|
||||
|
||||
assertNull(result.first());
|
||||
assertNull(result.second());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGetDummyTags_ContainsRootTag() {
|
||||
|
|
|
|||
|
|
@ -18,11 +18,21 @@
|
|||
package org.apache.cloudstack.veeam.api.dto;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import com.cloud.utils.Pair;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class OvfXmlUtilTest {
|
||||
|
||||
|
|
@ -42,4 +52,29 @@ public class OvfXmlUtilTest {
|
|||
assertEquals("1", vm.getCpu().getTopology().getCores());
|
||||
assertEquals("1", vm.getCpu().getTopology().getThreads());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_restoreConfig_parse() throws Exception {
|
||||
Vm vm = mock(Vm.class);
|
||||
Vm.Initialization initialization = mock(Vm.Initialization.class);
|
||||
Vm.Initialization.Configuration configMock = mock(Vm.Initialization.Configuration.class);
|
||||
when(initialization.getConfiguration()).thenReturn(configMock);
|
||||
when(vm.getInitialization()).thenReturn(initialization);
|
||||
String ovfXml;
|
||||
try (InputStream is = getClass().getClassLoader().getResourceAsStream("test-ovf.xml")) {
|
||||
assertNotNull(is);
|
||||
ovfXml = new String(is.readAllBytes(), StandardCharsets.UTF_8);
|
||||
}
|
||||
when(configMock.getData()).thenReturn(ovfXml);
|
||||
|
||||
String instanceConfig = OvfXmlUtil.getConfigMetadataXml(vm, mock(Logger.class));
|
||||
assertNotNull(instanceConfig);
|
||||
assertTrue(instanceConfig.contains("ovf:CloudStackMetadata_Type"));
|
||||
assertTrue(instanceConfig.contains("<NetworkId>6965c1cf-8d44-4622-82e2-4dbbe4a58355</NetworkId>"));
|
||||
|
||||
Pair<String, String> result = OvfXmlUtil.getVmNicDetailFromStoredConfig(instanceConfig, "6965c1cf-8d44-4622-82e2-4dbbe4a58355", mock(Logger.class));
|
||||
assertNotNull(result);
|
||||
assertEquals("1e:01:50:00:00:fd", result.first());
|
||||
assertEquals("10.1.1.103", result.second());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,225 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<ovf:Envelope
|
||||
xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1/"
|
||||
xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
|
||||
xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ovf:version="4.4.0.0">
|
||||
<References>
|
||||
<File ovf:href="6af2dd24-1af2-3610-b7b8-de38c98ec958/2efdaae2-6c38-4ac8-ac75-562cf47adba1" ovf:id="2efdaae2-6c38-4ac8-ac75-562cf47adba1" ovf:size="4096" ovf:description="Active VM" ovf:disk_storage_type="IMAGE" ovf:cinder_volume_type=""></File>
|
||||
</References>
|
||||
<NetworkSection>
|
||||
<Info>List of networks</Info>
|
||||
<Network ovf:name="Network-85990692-f734-4695-afe4-aca34a21f459">
|
||||
<Description></Description>
|
||||
</Network>
|
||||
</NetworkSection>
|
||||
<Section xsi:type="ovf:DiskSection_Type">
|
||||
<Info>List of Virtual Disks</Info>
|
||||
<Disk ovf:diskId="2efdaae2-6c38-4ac8-ac75-562cf47adba1" ovf:size="1" ovf:actual_size="1" ovf:vm_snapshot_id="dfa11f00-f92d-353b-8dbe-a653a0a4315b" ovf:parentRef="" ovf:fileRef="6af2dd24-1af2-3610-b7b8-de38c98ec958/2efdaae2-6c38-4ac8-ac75-562cf47adba1" ovf:format="http://www.vmware.com/specifications/vmdk.html#sparse" ovf:volume-format="COW" ovf:volume-type="Sparse" ovf:disk-interface="VirtIO_SCSI" ovf:read-only="false" ovf:shareable="false" ovf:boot="true" ovf:pass-discard="false" ovf:incremental-backup="false" ovf:disk-alias="ROOT-27" ovf:disk-description="ROOT-27" ovf:wipe-after-delete="false"></Disk>
|
||||
</Section>
|
||||
<Section xsi:type="ovf:CloudStackMetadata_Type">
|
||||
<Info>CloudStack specific metadata</Info>
|
||||
<CloudStack>
|
||||
<AccountId>048531b6-4386-11f1-930c-525400580bd0</AccountId>
|
||||
<DomainId>e0afbb58-4385-11f1-930c-525400580bd0</DomainId>
|
||||
<ProjectId></ProjectId>
|
||||
<ServiceOfferingId>ac3edee0-e2fb-4cd1-b6d4-d3b4555203ba</ServiceOfferingId>
|
||||
<DataDiskOfferingIdMap>
|
||||
<Entry>
|
||||
<DiskId>2efdaae2-6c38-4ac8-ac75-562cf47adba1</DiskId>
|
||||
<OfferingId>4de70249-b89d-4f08-9ca2-05ddb4ad1b2a</OfferingId>
|
||||
</Entry>
|
||||
</DataDiskOfferingIdMap>
|
||||
<Details>
|
||||
<Detail>
|
||||
<Key>keyboard</Key>
|
||||
<Value>us</Value>
|
||||
</Detail>
|
||||
<Detail>
|
||||
<Key>skip.force.disk.controller</Key>
|
||||
<Value>true</Value>
|
||||
</Detail>
|
||||
<Detail>
|
||||
<Key>nicAdapter</Key>
|
||||
<Value>virtio</Value>
|
||||
</Detail>
|
||||
<Detail>
|
||||
<Key>rootDiskController</Key>
|
||||
<Value>osdefault</Value>
|
||||
</Detail>
|
||||
</Details>
|
||||
<Nics>
|
||||
<Nic>
|
||||
<Id>85990692-f734-4695-afe4-aca34a21f459</Id>
|
||||
<NetworkId>6aff2178-a323-4148-a592-edbd47b93229</NetworkId>
|
||||
<MACAddress>02:01:00:cf:00:05</MACAddress>
|
||||
<Ip4Address>10.1.1.40</Ip4Address>
|
||||
<Ip6Address></Ip6Address>
|
||||
</Nic>
|
||||
</Nics>
|
||||
</CloudStack>
|
||||
</Section>
|
||||
<Content ovf:id="out" xsi:type="ovf:VirtualSystem_Type">
|
||||
<Name>test-vm1</Name>
|
||||
<Description>test-vm1</Description>
|
||||
<Comment></Comment>
|
||||
<CreationDate>2026/05/06 18:29:58</CreationDate>
|
||||
<ExportDate>2026/05/06 18:47:55</ExportDate>
|
||||
<DeleteProtected>false</DeleteProtected>
|
||||
<SsoMethod>guest_agent</SsoMethod>
|
||||
<IsSmartcardEnabled>false</IsSmartcardEnabled>
|
||||
<NumOfIoThreads>1</NumOfIoThreads>
|
||||
<TimeZone>Etc/GMT</TimeZone>
|
||||
<default_boot_sequence>0</default_boot_sequence>
|
||||
<Generation>11</Generation>
|
||||
<ClusterCompatibilityVersion>4.8</ClusterCompatibilityVersion>
|
||||
<VmType>1</VmType>
|
||||
<ResumeBehavior>AUTO_RESUME</ResumeBehavior>
|
||||
<MinAllocatedMem>512</MinAllocatedMem>
|
||||
<IsStateless>false</IsStateless>
|
||||
<IsRunAndPause>false</IsRunAndPause>
|
||||
<AutoStartup>false</AutoStartup>
|
||||
<Priority>0</Priority>
|
||||
<CreatedByUserId>048531b6-4386-11f1-930c-525400580bd0</CreatedByUserId>
|
||||
<MigrationSupport>0</MigrationSupport>
|
||||
<IsBootMenuEnabled>false</IsBootMenuEnabled>
|
||||
<IsSpiceFileTransferEnabled>true</IsSpiceFileTransferEnabled>
|
||||
<IsSpiceCopyPasteEnabled>true</IsSpiceCopyPasteEnabled>
|
||||
<AllowConsoleReconnect>false</AllowConsoleReconnect>
|
||||
<ConsoleDisconnectAction>LOCK_SCREEN</ConsoleDisconnectAction>
|
||||
<ConsoleDisconnectActionDelay>0</ConsoleDisconnectActionDelay>
|
||||
<CustomEmulatedMachine></CustomEmulatedMachine>
|
||||
<BiosType>3</BiosType>
|
||||
<CustomCpuName></CustomCpuName>
|
||||
<PredefinedProperties></PredefinedProperties>
|
||||
<UserDefinedProperties></UserDefinedProperties>
|
||||
<MaxMemorySizeMb>512</MaxMemorySizeMb>
|
||||
<MultiQueuesEnabled>true</MultiQueuesEnabled>
|
||||
<VirtioScsiMultiQueuesEnabled>false</VirtioScsiMultiQueuesEnabled>
|
||||
<UseHostCpu>false</UseHostCpu>
|
||||
<BalloonEnabled>false</BalloonEnabled>
|
||||
<CpuPinningPolicy>0</CpuPinningPolicy>
|
||||
<ClusterName></ClusterName>
|
||||
<TemplateId>8c367ed8-03d9-4c02-a4a4-f20b796f1b56</TemplateId>
|
||||
<TemplateName>8c367ed8-03d9-4c02-a4a4-f20b796f1b56</TemplateName>
|
||||
<IsInitilized>true</IsInitilized>
|
||||
<Origin>3</Origin>
|
||||
<quota_id>00000000-0000-0000-0000-000000000000</quota_id>
|
||||
<DefaultDisplayType>2</DefaultDisplayType>
|
||||
<TrustedService>false</TrustedService>
|
||||
<OriginalTemplateId>8c367ed8-03d9-4c02-a4a4-f20b796f1b56</OriginalTemplateId>
|
||||
<OriginalTemplateName>8c367ed8-03d9-4c02-a4a4-f20b796f1b56</OriginalTemplateName>
|
||||
<UseLatestVersion>false</UseLatestVersion>
|
||||
<StopTime>2026/05/06 18:29:58</StopTime>
|
||||
<BootTime>2026/05/06 18:29:58</BootTime>
|
||||
<Downtime>0</Downtime>
|
||||
<Section ovf:id="649d4d91-7cad-4541-a0a4-3930472f95ec" ovf:required="false" xsi:type="ovf:OperatingSystemSection_Type">
|
||||
<Info>Guest Operating System</Info>
|
||||
<Description>linux</Description>
|
||||
</Section>
|
||||
<Section xsi:type="ovf:VirtualHardwareSection_Type">
|
||||
<Info>1 CPU, 512 Memory</Info>
|
||||
<System>
|
||||
<vssd:VirtualSystemType>ENGINE 4.4.0.0</vssd:VirtualSystemType>
|
||||
</System>
|
||||
<Item>
|
||||
<rasd:Caption>1 virtual cpu</rasd:Caption>
|
||||
<rasd:Description>Number of virtual CPU</rasd:Description>
|
||||
<rasd:InstanceId>1</rasd:InstanceId>
|
||||
<rasd:ResourceType>3</rasd:ResourceType>
|
||||
<rasd:num_of_sockets>1</rasd:num_of_sockets>
|
||||
<rasd:cpu_per_socket>1</rasd:cpu_per_socket>
|
||||
<rasd:threads_per_cpu>1</rasd:threads_per_cpu>
|
||||
<rasd:max_num_of_vcpus>1</rasd:max_num_of_vcpus>
|
||||
<rasd:VirtualQuantity>1</rasd:VirtualQuantity>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:Caption>512 MB of memory</rasd:Caption>
|
||||
<rasd:Description>Memory Size</rasd:Description>
|
||||
<rasd:InstanceId>2</rasd:InstanceId>
|
||||
<rasd:ResourceType>4</rasd:ResourceType>
|
||||
<rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>
|
||||
<rasd:VirtualQuantity>512</rasd:VirtualQuantity>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:Caption>ROOT-27</rasd:Caption>
|
||||
<rasd:InstanceId>2efdaae2-6c38-4ac8-ac75-562cf47adba1</rasd:InstanceId>
|
||||
<rasd:ResourceType>17</rasd:ResourceType>
|
||||
<rasd:HostResource>6af2dd24-1af2-3610-b7b8-de38c98ec958/2efdaae2-6c38-4ac8-ac75-562cf47adba1</rasd:HostResource>
|
||||
<rasd:Parent>00000000-0000-0000-0000-000000000000</rasd:Parent>
|
||||
<rasd:Template>8c367ed8-03d9-4c02-a4a4-f20b796f1b56</rasd:Template>
|
||||
<rasd:ApplicationList></rasd:ApplicationList>
|
||||
<rasd:StorageId>6af2dd24-1af2-3610-b7b8-de38c98ec958</rasd:StorageId>
|
||||
<rasd:StoragePoolId>00000000-0000-0000-0000-000000000000</rasd:StoragePoolId>
|
||||
<rasd:CreationDate>2026/05/06 18:29:58</rasd:CreationDate>
|
||||
<rasd:LastModified>2026/05/06 18:47:55</rasd:LastModified>
|
||||
<rasd:last_modified_date>2026/05/06 18:47:55</rasd:last_modified_date>
|
||||
<Type>disk</Type>
|
||||
<Device>disk</Device>
|
||||
<rasd:Address>{type=drive, bus=0, controller=0, target=0, unit=0}</rasd:Address>
|
||||
<BootOrder>1</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>ua-6af2dd24-1af2-3610-b7b8-de38c98ec958/2efdaae2-6c38-4ac8-ac75-562cf47adba1</Alias>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:Caption>Ethernet adapter - ExternalGuestNetworkGuru</rasd:Caption>
|
||||
<rasd:InstanceId>85990692-f734-4695-afe4-aca34a21f459</rasd:InstanceId>
|
||||
<rasd:ResourceType>10</rasd:ResourceType>
|
||||
<rasd:OtherResourceType></rasd:OtherResourceType>
|
||||
<rasd:ResourceSubType>3</rasd:ResourceSubType>
|
||||
<rasd:Connection>Network-85990692-f734-4695-afe4-aca34a21f459</rasd:Connection>
|
||||
<rasd:Linked>true</rasd:Linked>
|
||||
<rasd:Name>ExternalGuestNetworkGuru</rasd:Name>
|
||||
<rasd:ElementName>6aff2178-a323-4148-a592-edbd47b93229</rasd:ElementName>
|
||||
<rasd:MACAddress>02:01:00:cf:00:05</rasd:MACAddress>
|
||||
<rasd:speed>10000</rasd:speed>
|
||||
<Type>interface</Type>
|
||||
<Device>bridge</Device>
|
||||
<rasd:Address>{type=pci, slot=0x00, bus=0x01, domain=0x0000, function=0x0}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>ua-85990692-f734-4695-afe4-aca34a21f459</Alias>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:Caption>USB Controller</rasd:Caption>
|
||||
<rasd:InstanceId>3</rasd:InstanceId>
|
||||
<rasd:ResourceType>23</rasd:ResourceType>
|
||||
<rasd:UsbPolicy>DISABLED</rasd:UsbPolicy>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>373a1bbf-b292-31c9-a29c-afeb9ba84c21</rasd:InstanceId>
|
||||
<Type>rng</Type>
|
||||
<Device>virtio</Device>
|
||||
<rasd:Address>{type=pci, slot=0x00, bus=0x06, domain=0x0000, function=0x0}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias></Alias>
|
||||
<SpecParams>
|
||||
<source>urandom</source>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
</Section>
|
||||
</Content>
|
||||
</ovf:Envelope>
|
||||
|
|
@ -627,4 +627,9 @@ public class MockAccountManager extends ManagerBase implements AccountManager {
|
|||
public User getOneActiveUserForAccount(Account account) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Account getAccountByUuid(String accountUuid) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2789,6 +2789,11 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
|
|||
return _accountDao.findByIdIncludingRemoved(accountId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Account getAccountByUuid(String accountUuid) {
|
||||
return _accountDao.findByUuidIncludingRemoved(accountUuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoleType getRoleType(Account account) {
|
||||
if (account == null) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue