mirror of https://github.com/apache/cloudstack.git
changes
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
This commit is contained in:
parent
0ff4dc5513
commit
f9070985d5
|
|
@ -60,4 +60,6 @@ public interface ResourceTagDao extends GenericDao<ResourceTagVO, Long> {
|
|||
void removeByResourceIdAndKey(long resourceId, ResourceObjectType resourceType, String key);
|
||||
|
||||
List<? extends ResourceTag> listByResourceUuid(String resourceUuid);
|
||||
|
||||
List<ResourceTagVO> listByResourceType(ResourceObjectType resourceType);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,4 +120,11 @@ public class ResourceTagsDaoImpl extends GenericDaoBase<ResourceTagVO, Long> imp
|
|||
sc.setParameters("resourceUuid", resourceUuid);
|
||||
return listBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ResourceTagVO> listByResourceType(ResourceObjectType resourceType) {
|
||||
SearchCriteria<ResourceTagVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("resourceType", resourceType);
|
||||
return listBy(sc);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
package org.apache.cloudstack.veeam.adapter;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.Collections;
|
||||
|
|
@ -75,6 +76,8 @@ import org.apache.cloudstack.jobs.JobInfo;
|
|||
import org.apache.cloudstack.query.QueryService;
|
||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||
import org.apache.cloudstack.veeam.VeeamControlService;
|
||||
import org.apache.cloudstack.veeam.api.TagsRouteHandler;
|
||||
import org.apache.cloudstack.veeam.api.converter.AsyncJobJoinVOToJobConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.BackupVOToBackupConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.ClusterVOToClusterConverter;
|
||||
|
|
@ -84,12 +87,14 @@ import org.apache.cloudstack.veeam.api.converter.ImageTransferVOToImageTransferC
|
|||
import org.apache.cloudstack.veeam.api.converter.NetworkVOToNetworkConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.NetworkVOToVnicProfileConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.NicVOToNicConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.ResourceTagVOToTagConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.StoreVOToStorageDomainConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.UserVmJoinVOToVmConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.UserVmVOToCheckpointConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.VmSnapshotVOToSnapshotConverter;
|
||||
import org.apache.cloudstack.veeam.api.converter.VolumeJoinVOToDiskConverter;
|
||||
import org.apache.cloudstack.veeam.api.dto.Backup;
|
||||
import org.apache.cloudstack.veeam.api.dto.BaseDto;
|
||||
import org.apache.cloudstack.veeam.api.dto.Checkpoint;
|
||||
import org.apache.cloudstack.veeam.api.dto.Cluster;
|
||||
import org.apache.cloudstack.veeam.api.dto.DataCenter;
|
||||
|
|
@ -100,9 +105,11 @@ import org.apache.cloudstack.veeam.api.dto.ImageTransfer;
|
|||
import org.apache.cloudstack.veeam.api.dto.Job;
|
||||
import org.apache.cloudstack.veeam.api.dto.Network;
|
||||
import org.apache.cloudstack.veeam.api.dto.Nic;
|
||||
import org.apache.cloudstack.veeam.api.dto.OvfXmlUtil;
|
||||
import org.apache.cloudstack.veeam.api.dto.ResourceAction;
|
||||
import org.apache.cloudstack.veeam.api.dto.Snapshot;
|
||||
import org.apache.cloudstack.veeam.api.dto.StorageDomain;
|
||||
import org.apache.cloudstack.veeam.api.dto.Tag;
|
||||
import org.apache.cloudstack.veeam.api.dto.Vm;
|
||||
import org.apache.cloudstack.veeam.api.dto.VmAction;
|
||||
import org.apache.cloudstack.veeam.api.dto.VnicProfile;
|
||||
|
|
@ -138,12 +145,15 @@ import com.cloud.network.dao.NetworkDao;
|
|||
import com.cloud.network.dao.NetworkVO;
|
||||
import com.cloud.offering.ServiceOffering;
|
||||
import com.cloud.org.Grouping;
|
||||
import com.cloud.server.ResourceTag;
|
||||
import com.cloud.service.dao.ServiceOfferingDao;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.storage.VolumeApiService;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.dao.VolumeDao;
|
||||
import com.cloud.storage.dao.VolumeDetailsDao;
|
||||
import com.cloud.tags.ResourceTagVO;
|
||||
import com.cloud.tags.dao.ResourceTagDao;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountService;
|
||||
import com.cloud.user.User;
|
||||
|
|
@ -266,8 +276,31 @@ public class ServerAdapter extends ManagerBase {
|
|||
@Inject
|
||||
BackupDao backupDao;
|
||||
|
||||
@Inject
|
||||
ResourceTagDao resourceTagDao;
|
||||
|
||||
//ToDo: check access on objects
|
||||
|
||||
protected static Tag getDummyTagByName(String name) {
|
||||
Tag tag = new Tag();
|
||||
String id = UUID.nameUUIDFromBytes(String.format("veeam:%s", name.toLowerCase()).getBytes()).toString();
|
||||
tag.setId(id);
|
||||
tag.setName(name);
|
||||
tag.setDescription(String.format("Default %s tag", name.toLowerCase()));
|
||||
tag.setHref(VeeamControlService.ContextPath.value() + TagsRouteHandler.BASE_ROUTE + "/" + id);
|
||||
tag.setParent(ResourceTagVOToTagConverter.getRootTagRef());
|
||||
return tag;
|
||||
}
|
||||
|
||||
protected static Map<String, Tag> getDummyTags() {
|
||||
Map<String, Tag> tags = new HashMap<>();
|
||||
Tag tag1 = getDummyTagByName("Automatic");
|
||||
tags.put(tag1.getId(), tag1);
|
||||
Tag tag2 = getDummyTagByName("Manual");
|
||||
tags.put(tag2.getId(), tag2);
|
||||
return tags;
|
||||
}
|
||||
|
||||
protected Role createServiceAccountRole() {
|
||||
Role role = roleService.createRole(SERVICE_ACCOUNT_ROLE_NAME, RoleType.User,
|
||||
SERVICE_ACCOUNT_ROLE_NAME, false);
|
||||
|
|
@ -417,20 +450,30 @@ public class ServerAdapter extends ManagerBase {
|
|||
return UserVmJoinVOToVmConverter.toVmList(vms, this::getHostById);
|
||||
}
|
||||
|
||||
public Vm getInstance(String uuid) {
|
||||
public Vm getInstance(String uuid, boolean includeDisks, boolean includeNics, boolean allContent) {
|
||||
UserVmJoinVO vo = userVmJoinDao.findByUuid(uuid);
|
||||
if (vo == null) {
|
||||
throw new InvalidParameterValueException("VM with ID " + uuid + " not found");
|
||||
}
|
||||
return UserVmJoinVOToVmConverter.toVm(vo, this::getHostById, this::listDiskAttachmentsByInstanceId,
|
||||
this::listNicsByInstance);
|
||||
return UserVmJoinVOToVmConverter.toVm(vo, this::getHostById,
|
||||
includeDisks ? this::listDiskAttachmentsByInstanceId : null,
|
||||
includeNics ? this::listNicsByInstance : null,
|
||||
allContent);
|
||||
}
|
||||
|
||||
public Vm createInstance(Vm request) {
|
||||
if (request == null) {
|
||||
throw new InvalidParameterValueException("Request disk data is empty");
|
||||
}
|
||||
OvfXmlUtil.updateFromConfiguration(request);
|
||||
String name = request.getName();
|
||||
if (StringUtils.isBlank(name)) {
|
||||
throw new InvalidParameterValueException("Invalid name specified for the VM");
|
||||
}
|
||||
String displayName = name;
|
||||
if (name.endsWith("_restored")) {
|
||||
name = name.replace("_restored", "-restored");
|
||||
}
|
||||
Long zoneId = null;
|
||||
Long clusterId = null;
|
||||
if (request.getCluster() != null && StringUtils.isNotEmpty(request.getCluster().getId())) {
|
||||
|
|
@ -446,14 +489,16 @@ public class ServerAdapter extends ManagerBase {
|
|||
Integer cpu = null;
|
||||
try {
|
||||
cpu = Integer.valueOf(request.getCpu().getTopology().getSockets());
|
||||
} catch (Exception ignored) {}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
if (cpu == null) {
|
||||
throw new InvalidParameterValueException("CPU topology sockets must be specified");
|
||||
}
|
||||
Long memory = null;
|
||||
try {
|
||||
memory = Long.valueOf(request.getMemory());
|
||||
} catch (Exception ignored) {}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
if (memory == null) {
|
||||
throw new InvalidParameterValueException("Memory must be specified");
|
||||
}
|
||||
|
|
@ -470,7 +515,7 @@ public class ServerAdapter extends ManagerBase {
|
|||
Pair<User, Account> serviceUserAccount = createServiceAccountIfNeeded();
|
||||
CallContext ctx = CallContext.register(serviceUserAccount.first(), serviceUserAccount.second());
|
||||
try {
|
||||
return createInstance(zoneId, clusterId, name, cpu, memory, userdata, bootType, bootMode);
|
||||
return createInstance(zoneId, clusterId, name, displayName, cpu, memory, userdata, bootType, bootMode);
|
||||
} finally {
|
||||
CallContext.unregister();
|
||||
}
|
||||
|
|
@ -491,8 +536,8 @@ public class ServerAdapter extends ManagerBase {
|
|||
return serviceOfferingDao.findByUuid(uuid);
|
||||
}
|
||||
|
||||
protected Vm createInstance(Long zoneId, Long clusterId, String name, int cpu, long memory, String userdata,
|
||||
ApiConstants.BootType bootType, ApiConstants.BootMode bootMode) {
|
||||
protected Vm createInstance(Long zoneId, Long clusterId, String name, String displayName, int cpu, long memory,
|
||||
String userdata, ApiConstants.BootType bootType, ApiConstants.BootMode bootMode) {
|
||||
ServiceOffering serviceOffering = getServiceOfferingIdForVmCreation(zoneId, cpu, memory);
|
||||
if (serviceOffering == null) {
|
||||
throw new CloudRuntimeException("No service offering found for VM creation with specified CPU and memory");
|
||||
|
|
@ -503,6 +548,9 @@ public class ServerAdapter extends ManagerBase {
|
|||
cmd.setZoneId(zoneId);
|
||||
cmd.setClusterId(clusterId);
|
||||
cmd.setName(name);
|
||||
if (displayName != null) {
|
||||
cmd.setDisplayName(displayName);
|
||||
}
|
||||
cmd.setServiceOfferingId(serviceOffering.getId());
|
||||
if (StringUtils.isNotEmpty(userdata)) {
|
||||
cmd.setUserData(Base64.getEncoder().encodeToString(userdata.getBytes(StandardCharsets.UTF_8)));
|
||||
|
|
@ -526,7 +574,7 @@ public class ServerAdapter extends ManagerBase {
|
|||
vm = userVmService.finalizeCreateVirtualMachine(vm.getId());
|
||||
UserVmJoinVO vo = userVmJoinDao.findById(vm.getId());
|
||||
return UserVmJoinVOToVmConverter.toVm(vo, this::getHostById, this::listDiskAttachmentsByInstanceId,
|
||||
this::listNicsByInstance);
|
||||
this::listNicsByInstance, false);
|
||||
} catch (InsufficientCapacityException | ResourceUnavailableException | ResourceAllocationException | CloudRuntimeException e) {
|
||||
throw new CloudRuntimeException("Failed to create VM: " + e.getMessage(), e);
|
||||
}
|
||||
|
|
@ -534,7 +582,7 @@ public class ServerAdapter extends ManagerBase {
|
|||
|
||||
public Vm updateInstance(String uuid, Vm request) {
|
||||
// ToDo: what to do?!
|
||||
return getInstance(uuid);
|
||||
return getInstance(uuid, false, false, false);
|
||||
}
|
||||
|
||||
public void deleteInstance(String uuid) {
|
||||
|
|
@ -1236,4 +1284,30 @@ public class ServerAdapter extends ManagerBase {
|
|||
CallContext.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Tag> listAllTags() {
|
||||
List<Tag> tags = new ArrayList<>(getDummyTags().values());
|
||||
List<ResourceTagVO> vmResourceTags = resourceTagDao.listByResourceType(ResourceTag.ResourceObjectType.UserVm);
|
||||
if (CollectionUtils.isNotEmpty(vmResourceTags)) {
|
||||
tags.addAll(ResourceTagVOToTagConverter.toTags(vmResourceTags));
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
public Tag getTag(String uuid) {
|
||||
if (BaseDto.ZERO_UUID.equals(uuid)) {
|
||||
return ResourceTagVOToTagConverter.getRootTag();
|
||||
}
|
||||
Tag tag = getDummyTags().get(uuid);
|
||||
if (tag == null) {
|
||||
ResourceTagVO resourceTagVO = resourceTagDao.findByUuid(uuid);
|
||||
if (resourceTagVO != null) {
|
||||
tag = ResourceTagVOToTagConverter.toTag(resourceTagVO);
|
||||
}
|
||||
}
|
||||
if (tag == null) {
|
||||
throw new InvalidParameterValueException("Tag with ID " + uuid + " not found");
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,102 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.veeam.api;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.cloudstack.veeam.RouteHandler;
|
||||
import org.apache.cloudstack.veeam.VeeamControlServlet;
|
||||
import org.apache.cloudstack.veeam.adapter.ServerAdapter;
|
||||
import org.apache.cloudstack.veeam.api.dto.NamedList;
|
||||
import org.apache.cloudstack.veeam.api.dto.Tag;
|
||||
import org.apache.cloudstack.veeam.utils.Negotiation;
|
||||
import org.apache.cloudstack.veeam.utils.PathUtil;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
|
||||
public class TagsRouteHandler extends ManagerBase implements RouteHandler {
|
||||
public static final String BASE_ROUTE = "/api/tags";
|
||||
|
||||
@Inject
|
||||
ServerAdapter serverAdapter;
|
||||
|
||||
@Override
|
||||
public boolean start() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int priority() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canHandle(String method, String path) {
|
||||
return getSanitizedPath(path).startsWith(BASE_ROUTE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(HttpServletRequest req, HttpServletResponse resp, String path, Negotiation.OutFormat outFormat,
|
||||
VeeamControlServlet io) throws IOException {
|
||||
final String method = req.getMethod();
|
||||
if (!"GET".equalsIgnoreCase(method)) {
|
||||
io.methodNotAllowed(resp, "GET", outFormat);
|
||||
return;
|
||||
}
|
||||
final String sanitizedPath = getSanitizedPath(path);
|
||||
if (sanitizedPath.equals(BASE_ROUTE)) {
|
||||
handleGet(req, resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
|
||||
if (CollectionUtils.isNotEmpty(idAndSubPath)) {
|
||||
String id = idAndSubPath.get(0);
|
||||
if (idAndSubPath.size() == 1) {
|
||||
handleGetById(id, resp, outFormat, io);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
io.notFound(resp, null, outFormat);
|
||||
}
|
||||
|
||||
protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
|
||||
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
|
||||
final List<Tag> result = serverAdapter.listAllTags();
|
||||
NamedList<Tag> response = NamedList.of("tag", result);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
}
|
||||
|
||||
protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
try {
|
||||
Tag response = serverAdapter.getTag(id);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
} catch (InvalidParameterValueException e) {
|
||||
io.notFound(resp, e.getMessage(), outFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -34,7 +34,6 @@ import org.apache.cloudstack.veeam.api.dto.Disk;
|
|||
import org.apache.cloudstack.veeam.api.dto.DiskAttachment;
|
||||
import org.apache.cloudstack.veeam.api.dto.NamedList;
|
||||
import org.apache.cloudstack.veeam.api.dto.Nic;
|
||||
import org.apache.cloudstack.veeam.api.dto.Nics;
|
||||
import org.apache.cloudstack.veeam.api.dto.ResourceAction;
|
||||
import org.apache.cloudstack.veeam.api.dto.Snapshot;
|
||||
import org.apache.cloudstack.veeam.api.dto.Vm;
|
||||
|
|
@ -46,6 +45,7 @@ import org.apache.cloudstack.veeam.api.request.VmSearchParser;
|
|||
import org.apache.cloudstack.veeam.utils.Negotiation;
|
||||
import org.apache.cloudstack.veeam.utils.PathUtil;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.utils.component.ManagerBase;
|
||||
|
|
@ -108,7 +108,7 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler {
|
|||
if (!"GET".equalsIgnoreCase(method) && !"PUT".equalsIgnoreCase(method) && !"DELETE".equalsIgnoreCase(method)) {
|
||||
io.methodNotAllowed(resp, "GET, PUT, DELETE", outFormat);
|
||||
} else if ("GET".equalsIgnoreCase(method)) {
|
||||
handleGetById(id, resp, outFormat, io);
|
||||
handleGetById(id, req, resp, outFormat, io);
|
||||
} else if ("PUT".equalsIgnoreCase(method)) {
|
||||
handleUpdateById(id, req, resp, outFormat, io);
|
||||
} else if ("DELETE".equalsIgnoreCase(method)) {
|
||||
|
|
@ -308,10 +308,22 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler {
|
|||
}
|
||||
}
|
||||
|
||||
protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
|
||||
final VeeamControlServlet io) throws IOException {
|
||||
protected void handleGetById(final String id, final HttpServletRequest req, final HttpServletResponse resp,
|
||||
final Negotiation.OutFormat outFormat, final VeeamControlServlet io) throws IOException {
|
||||
String followStr = req.getParameter("follow");
|
||||
boolean includeDisks = false;
|
||||
boolean includeNics = false;
|
||||
if (StringUtils.isNotBlank(followStr)) {
|
||||
Set<String> followParts = java.util.Arrays.stream(followStr.split(","))
|
||||
.map(String::trim)
|
||||
.filter(s -> !s.isEmpty())
|
||||
.collect(java.util.stream.Collectors.toSet());
|
||||
includeDisks = followParts.contains("disk_attachments.disk");
|
||||
includeNics = followParts.contains("nics.reporteddevices");
|
||||
}
|
||||
boolean allContent = Boolean.parseBoolean(req.getParameter("all_content"));
|
||||
try {
|
||||
Vm response = serverAdapter.getInstance(id);
|
||||
Vm response = serverAdapter.getInstance(id, includeDisks, includeNics, allContent);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
} catch (InvalidParameterValueException e) {
|
||||
io.notFound(resp, e.getMessage(), outFormat);
|
||||
|
|
@ -399,7 +411,7 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler {
|
|||
final VeeamControlServlet io) throws IOException {
|
||||
try {
|
||||
List<Nic> nics = serverAdapter.listNicsByInstanceUuid(id);
|
||||
Nics response = new Nics(nics);
|
||||
NamedList<Nic> response = NamedList.of("nic", nics);
|
||||
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
|
||||
} catch (InvalidParameterValueException e) {
|
||||
io.notFound(resp, e.getMessage(), outFormat);
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ public class AsyncJobJoinVOToJobConverter {
|
|||
public static VmAction toVmAction(final AsyncJobJoinVO vo, final UserVmJoinVO vm) {
|
||||
VmAction action = new VmAction();
|
||||
fillAction(action, vo);
|
||||
action.setVm(UserVmJoinVOToVmConverter.toVm(vm, null, null, null));
|
||||
action.setVm(UserVmJoinVOToVmConverter.toVm(vm, null, null, null, false));
|
||||
return action;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.veeam.api.converter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.cloudstack.veeam.VeeamControlService;
|
||||
import org.apache.cloudstack.veeam.api.TagsRouteHandler;
|
||||
import org.apache.cloudstack.veeam.api.VmsRouteHandler;
|
||||
import org.apache.cloudstack.veeam.api.dto.BaseDto;
|
||||
import org.apache.cloudstack.veeam.api.dto.Ref;
|
||||
import org.apache.cloudstack.veeam.api.dto.Tag;
|
||||
|
||||
import com.cloud.server.ResourceTag;
|
||||
import com.cloud.tags.ResourceTagVO;
|
||||
|
||||
public class ResourceTagVOToTagConverter {
|
||||
|
||||
public static Ref getRootTagRef() {
|
||||
String basePath = VeeamControlService.ContextPath.value();
|
||||
return Ref.of(basePath + TagsRouteHandler.BASE_ROUTE + "/" + BaseDto.ZERO_UUID, BaseDto.ZERO_UUID);
|
||||
}
|
||||
|
||||
public static Tag getRootTag() {
|
||||
String basePath = VeeamControlService.ContextPath.value();
|
||||
Tag tag = new Tag();
|
||||
tag.setId(BaseDto.ZERO_UUID);
|
||||
tag.setName("root");
|
||||
tag.setHref(getRootTagRef().getHref());
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static Tag toTag(ResourceTagVO vo) {
|
||||
String basePath = VeeamControlService.ContextPath.value();
|
||||
Tag tag = new Tag();
|
||||
tag.setId(vo.getUuid());
|
||||
tag.setName(vo.getKey());
|
||||
tag.setDescription(String.format("Tag %s-%s", vo.getKey(), vo.getValue()));
|
||||
tag.setHref(basePath + TagsRouteHandler.BASE_ROUTE + "/" + vo.getUuid());
|
||||
if (ResourceTag.ResourceObjectType.UserVm.equals(vo.getResourceType())) {
|
||||
tag.setVm(Ref.of(basePath + VmsRouteHandler.BASE_ROUTE + "/" + vo.getResourceUuid(),
|
||||
vo.getResourceUuid()));
|
||||
}
|
||||
tag.setParent(getRootTagRef());
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static List<Tag> toTags(List<ResourceTagVO> vos) {
|
||||
return vos.stream().map(ResourceTagVOToTagConverter::toTag).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
|
@ -27,14 +27,13 @@ import org.apache.cloudstack.veeam.VeeamControlService;
|
|||
import org.apache.cloudstack.veeam.api.ApiService;
|
||||
import org.apache.cloudstack.veeam.api.VmsRouteHandler;
|
||||
import org.apache.cloudstack.veeam.api.dto.BaseDto;
|
||||
import org.apache.cloudstack.veeam.api.dto.Bios;
|
||||
import org.apache.cloudstack.veeam.api.dto.Cpu;
|
||||
import org.apache.cloudstack.veeam.api.dto.DiskAttachment;
|
||||
import org.apache.cloudstack.veeam.api.dto.EmptyElement;
|
||||
import org.apache.cloudstack.veeam.api.dto.NamedList;
|
||||
import org.apache.cloudstack.veeam.api.dto.Nic;
|
||||
import org.apache.cloudstack.veeam.api.dto.Nics;
|
||||
import org.apache.cloudstack.veeam.api.dto.Os;
|
||||
import org.apache.cloudstack.veeam.api.dto.OvfXmlUtil;
|
||||
import org.apache.cloudstack.veeam.api.dto.Ref;
|
||||
import org.apache.cloudstack.veeam.api.dto.Topology;
|
||||
import org.apache.cloudstack.veeam.api.dto.Vm;
|
||||
|
|
@ -55,7 +54,9 @@ public final class UserVmJoinVOToVmConverter {
|
|||
* @param src UserVmJoinVO
|
||||
*/
|
||||
public static Vm toVm(final UserVmJoinVO src, final Function<Long, HostJoinVO> hostResolver,
|
||||
final Function<Long, List<DiskAttachment>> disksResolver, final Function<UserVmJoinVO, List<Nic>> nicsResolver) {
|
||||
final Function<Long, List<DiskAttachment>> disksResolver,
|
||||
final Function<UserVmJoinVO, List<Nic>> nicsResolver,
|
||||
final boolean allContent) {
|
||||
if (src == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -104,7 +105,13 @@ public final class UserVmJoinVOToVmConverter {
|
|||
}
|
||||
}
|
||||
|
||||
dst.setMemory(String.valueOf(src.getRamSize() * 1024L * 1024L));
|
||||
String memory = String.valueOf(src.getRamSize() * 1024L * 1024L);
|
||||
dst.setMemory(memory);
|
||||
Vm.MemoryPolicy memoryPolicy = new Vm.MemoryPolicy();
|
||||
memoryPolicy.setGuaranteed(memory);
|
||||
memoryPolicy.setMax(memory);
|
||||
memoryPolicy.setBallooning("false");
|
||||
dst.setMemoryPolicy(memoryPolicy);
|
||||
Cpu cpu = new Cpu();
|
||||
cpu.setArchitecture(src.getArch());
|
||||
cpu.setTopology(new Topology(src.getCpu(), 1, 1));
|
||||
|
|
@ -113,9 +120,15 @@ public final class UserVmJoinVOToVmConverter {
|
|||
os.setType(src.getGuestOsId() % 2 == 0
|
||||
? "windows"
|
||||
: "linux");
|
||||
Os.Boot boot = new Os.Boot();
|
||||
boot.setDevices(NamedList.of("device", List.of("hd")));
|
||||
os.setBoot(boot);
|
||||
dst.setOs(os);
|
||||
Bios bios = new Bios();
|
||||
Vm.Bios bios = new Vm.Bios();
|
||||
bios.setType("q35_secure_boot");
|
||||
Vm.Bios.BootMenu bootMenu = new Vm.Bios.BootMenu();
|
||||
bootMenu.setEnabled("false");
|
||||
bios.setBootMenu(bootMenu);
|
||||
dst.setBios(bios);
|
||||
dst.setType("desktop");
|
||||
dst.setOrigin("ovirt");
|
||||
|
|
@ -126,9 +139,9 @@ public final class UserVmJoinVOToVmConverter {
|
|||
dst.setDiskAttachments(NamedList.of("disk_attachment", diskAttachments));
|
||||
}
|
||||
|
||||
if (disksResolver != null) {
|
||||
if (nicsResolver != null) {
|
||||
List<Nic> nics = nicsResolver.apply(src);
|
||||
dst.setNics(new Nics(nics));
|
||||
dst.setNics(NamedList.of("nic", nics));
|
||||
}
|
||||
|
||||
dst.setActions(NamedList.of("link", List.of(
|
||||
|
|
@ -143,13 +156,29 @@ public final class UserVmJoinVOToVmConverter {
|
|||
BaseDto.getActionLink("snapshots", dst.getHref())
|
||||
));
|
||||
dst.setTags(new EmptyElement());
|
||||
dst.setCpuProfile(Ref.of(
|
||||
basePath + ApiService.BASE_ROUTE + "/cpuprofiles/" + src.getServiceOfferingUuid(),
|
||||
src.getServiceOfferingUuid()));
|
||||
if (allContent) {
|
||||
dst.setInitialization(getOvfInitialization(dst));
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
private static Vm.Initialization getOvfInitialization(Vm vm) {
|
||||
final Vm.Initialization.Configuration configuration = new Vm.Initialization.Configuration();
|
||||
configuration.setType("ovf");
|
||||
configuration.setData(OvfXmlUtil.toXml(vm));
|
||||
|
||||
final Vm.Initialization initialization = new Vm.Initialization();
|
||||
initialization.setConfiguration(configuration);
|
||||
return initialization;
|
||||
}
|
||||
|
||||
public static List<Vm> toVmList(final List<UserVmJoinVO> srcList, final Function<Long, HostJoinVO> hostResolver) {
|
||||
return srcList.stream()
|
||||
.map(v -> toVm(v, hostResolver, null, null))
|
||||
.map(v -> toVm(v, hostResolver, null, null, false))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ import com.fasterxml.jackson.annotation.JsonInclude;
|
|||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class BaseDto {
|
||||
|
||||
public static final String ZERO_UUID = "00000000-0000-0000-0000-000000000000";
|
||||
|
||||
private String href;
|
||||
private String id;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.veeam.api.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class BootMenu {
|
||||
|
||||
private String enabled = "false";
|
||||
|
||||
public String getEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(String enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.veeam.api.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class HardwareInformation {
|
||||
private String manufacturer;
|
||||
private String productName;
|
||||
private String serialNumber;
|
||||
private String uuid;
|
||||
private String version;
|
||||
|
||||
public String getManufacturer() {
|
||||
return manufacturer;
|
||||
}
|
||||
|
||||
public void setManufacturer(String manufacturer) {
|
||||
this.manufacturer = manufacturer;
|
||||
}
|
||||
|
||||
public String getProductName() {
|
||||
return productName;
|
||||
}
|
||||
|
||||
public void setProductName(String productName) {
|
||||
this.productName = productName;
|
||||
}
|
||||
|
||||
public String getSerialNumber() {
|
||||
return serialNumber;
|
||||
}
|
||||
|
||||
public void setSerialNumber(String serialNumber) {
|
||||
this.serialNumber = serialNumber;
|
||||
}
|
||||
|
||||
public String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public void setUuid(String uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
|
|
@ -259,4 +259,53 @@ public class Host extends BaseDto {
|
|||
public void setLink(List<Link> link) {
|
||||
this.link = link;
|
||||
}
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public static class HardwareInformation {
|
||||
private String manufacturer;
|
||||
private String productName;
|
||||
private String serialNumber;
|
||||
private String uuid;
|
||||
private String version;
|
||||
|
||||
public String getManufacturer() {
|
||||
return manufacturer;
|
||||
}
|
||||
|
||||
public void setManufacturer(String manufacturer) {
|
||||
this.manufacturer = manufacturer;
|
||||
}
|
||||
|
||||
public String getProductName() {
|
||||
return productName;
|
||||
}
|
||||
|
||||
public void setProductName(String productName) {
|
||||
this.productName = productName;
|
||||
}
|
||||
|
||||
public String getSerialNumber() {
|
||||
return serialNumber;
|
||||
}
|
||||
|
||||
public void setSerialNumber(String serialNumber) {
|
||||
this.serialNumber = serialNumber;
|
||||
}
|
||||
|
||||
public String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public void setUuid(String uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,57 +0,0 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.veeam.api.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class HostSummary {
|
||||
@JsonProperty("active")
|
||||
private String active;
|
||||
|
||||
@JsonProperty("migrating")
|
||||
private String migrating;
|
||||
|
||||
@JsonProperty("total")
|
||||
private String total;
|
||||
|
||||
public String getActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
public void setActive(String active) {
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
public String getMigrating() {
|
||||
return migrating;
|
||||
}
|
||||
|
||||
public void setMigrating(String migrating) {
|
||||
this.migrating = migrating;
|
||||
}
|
||||
|
||||
public String getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
public void setTotal(String total) {
|
||||
this.total = total;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.veeam.api.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JacksonXmlRootElement(localName = "nics")
|
||||
public final class Nics {
|
||||
|
||||
@JsonProperty("nic")
|
||||
@JacksonXmlElementWrapper(useWrapping = false)
|
||||
public List<Nic> nic;
|
||||
|
||||
public Nics() {
|
||||
}
|
||||
|
||||
public Nics(final List<Nic> nic) {
|
||||
this.nic = nic;
|
||||
}
|
||||
}
|
||||
|
|
@ -22,6 +22,8 @@ import com.fasterxml.jackson.annotation.JsonInclude;
|
|||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public final class Os {
|
||||
private String type;
|
||||
private String version;
|
||||
private Boot boot;
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
|
|
@ -30,4 +32,24 @@ public final class Os {
|
|||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Boot getBoot() {
|
||||
return boot;
|
||||
}
|
||||
|
||||
public void setBoot(Boot boot) {
|
||||
this.boot = boot;
|
||||
}
|
||||
|
||||
public final static class Boot {
|
||||
private NamedList<String> devices;
|
||||
|
||||
public NamedList<String> getDevices() {
|
||||
return devices;
|
||||
}
|
||||
|
||||
public void setDevices(NamedList<String> devices) {
|
||||
this.devices = devices;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,671 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.veeam.api.dto;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.namespace.NamespaceContext;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
public class OvfXmlUtil {
|
||||
|
||||
private static final String NS_OVF = "http://schemas.dmtf.org/ovf/envelope/1/";
|
||||
private static final String NS_RASD = "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData";
|
||||
private static final String NS_VSSD = "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData";
|
||||
private static final String NS_XSI = "http://www.w3.org/2001/XMLSchema-instance";
|
||||
|
||||
private static final String ZERO_UUID = "00000000-0000-0000-0000-000000000000";
|
||||
private static final TimeZone UTC = TimeZone.getTimeZone("Etc/GMT");
|
||||
|
||||
private static final ThreadLocal<SimpleDateFormat> OVIRT_DTF = ThreadLocal.withInitial(() -> {
|
||||
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.ROOT);
|
||||
sdf.setTimeZone(UTC);
|
||||
return sdf;
|
||||
});
|
||||
|
||||
public static String toXml(final Vm vm) {
|
||||
final String vmId = vm.getId();
|
||||
final String vmName = vm.getName();
|
||||
final String vmDesc = defaultString(vm.getDescription());
|
||||
|
||||
final long creationMillis = vm.getCreationTime();
|
||||
final String creationDate = formatDate(creationMillis);
|
||||
final String exportDate = formatDate(System.currentTimeMillis());
|
||||
final String stopTime = vm.getStopTime() != null ? formatDate(vm.getStopTime()) : creationDate;
|
||||
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));
|
||||
|
||||
// CPU: topology cores/sockets/threads. We default sockets=1 threads=1.
|
||||
final int vcpu = Math.max(1, Integer.parseInt(vm.getCpu().getTopology().getCores()));
|
||||
final int sockets = Math.max(1, Integer.parseInt(vm.getCpu().getTopology().getSockets()));
|
||||
final int threads = Math.max(1, Integer.parseInt(vm.getCpu().getTopology().getThreads()));
|
||||
final int cpuPerSocket = Math.max(1, vcpu / sockets);
|
||||
final int maxVcpu = vcpu;
|
||||
|
||||
// Template
|
||||
final Ref template = vm.getTemplate();
|
||||
final String templateId = template != null && StringUtils.isNotBlank(template.getId()) ? template.getId() : ZERO_UUID;
|
||||
final String templateName = template != null ? defaultString(template.getId()) : "Blank";
|
||||
|
||||
// Snapshot id (stable per VM id)
|
||||
final String snapshotId = UUID.nameUUIDFromBytes(("ovf-snap-" + vmId).getBytes(StandardCharsets.UTF_8)).toString();
|
||||
|
||||
final StringBuilder sb = new StringBuilder(16_384);
|
||||
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
sb.append("<ovf:Envelope ");
|
||||
sb.append("xmlns:ovf=\"").append(NS_OVF).append("\" ");
|
||||
sb.append("xmlns:rasd=\"").append(NS_RASD).append("\" ");
|
||||
sb.append("xmlns:vssd=\"").append(NS_VSSD).append("\" ");
|
||||
sb.append("xmlns:xsi=\"").append(NS_XSI).append("\" ovf:version=\"4.4.0.0\">");
|
||||
|
||||
// --- References (from disks) ---
|
||||
sb.append("<References>");
|
||||
for (DiskAttachment da : diskAttachments(vm)) {
|
||||
if (da == null || da.getDisk() == null || StringUtils.isBlank(da.getDisk().getId())) {
|
||||
continue;
|
||||
}
|
||||
final String diskId = da.getDisk().getId();
|
||||
final String storageDomainId = firstStorageDomainId(da.getDisk());
|
||||
final String href = storageDomainId + "/" + diskId;
|
||||
sb.append("<File ovf:href=\"").append(escapeAttr(href))
|
||||
.append("\" ovf:id=\"").append(escapeAttr(diskId))
|
||||
.append("\" ovf:size=\"4096\" ovf:description=\"Active VM\" ovf:disk_storage_type=\"IMAGE\" ovf:cinder_volume_type=\"\"></File>");
|
||||
}
|
||||
sb.append("</References>");
|
||||
|
||||
// --- NetworkSection ---
|
||||
sb.append("<NetworkSection>");
|
||||
sb.append("<Info>List of networks</Info>");
|
||||
// oVirt often lists networks, but can also be empty. We'll include known names if we can.
|
||||
for (Nic nic : nics(vm)) {
|
||||
if (nic == null) {
|
||||
continue;
|
||||
}
|
||||
final String netName = inferNetworkName(nic);
|
||||
if (StringUtils.isBlank(netName)) {
|
||||
continue;
|
||||
}
|
||||
sb.append("<Network ovf:name=\"").append(escapeAttr(netName)).append("\">");
|
||||
sb.append("<Description>").append(escapeText(defaultString(nic.getDescription()))).append("</Description>");
|
||||
sb.append("</Network>");
|
||||
}
|
||||
sb.append("</NetworkSection>");
|
||||
|
||||
// --- DiskSection ---
|
||||
sb.append("<Section xsi:type=\"ovf:DiskSection_Type\">");
|
||||
sb.append("<Info>List of Virtual Disks</Info>");
|
||||
for (DiskAttachment da : diskAttachments(vm)) {
|
||||
if (da == null || da.getDisk() == null || StringUtils.isBlank(da.getDisk().getId())) {
|
||||
continue;
|
||||
}
|
||||
final org.apache.cloudstack.veeam.api.dto.Disk d = da.getDisk();
|
||||
final String diskId = d.getId();
|
||||
final String storageDomainId = firstStorageDomainId(d);
|
||||
final String href = storageDomainId + "/" + diskId;
|
||||
final long provBytes = parseLong(d.getProvisionedSize(), 0);
|
||||
final long actualBytes = parseLong(d.getActualSize(), 0);
|
||||
final long provGiB = bytesToGibCeil(provBytes);
|
||||
final long actualGiB = bytesToGibCeil(actualBytes);
|
||||
final String diskInterface = mapDiskInterface(da.getIface());
|
||||
|
||||
sb.append("<Disk");
|
||||
sb.append(" ovf:diskId=\"").append(escapeAttr(diskId)).append("\"");
|
||||
sb.append(" ovf:size=\"").append(provGiB > 0 ? provGiB : 1).append("\"");
|
||||
sb.append(" ovf:actual_size=\"").append(actualGiB > 0 ? actualGiB : 1).append("\"");
|
||||
sb.append(" ovf:vm_snapshot_id=\"").append(escapeAttr(snapshotId)).append("\"");
|
||||
sb.append(" ovf:parentRef=\"\"");
|
||||
sb.append(" ovf:fileRef=\"").append(escapeAttr(href)).append("\"");
|
||||
sb.append(" ovf:format=\"").append(escapeAttr(mapOvfDiskFormat(d.getFormat(), d.getSparse()))).append("\"");
|
||||
sb.append(" ovf:volume-format=\"").append(escapeAttr(mapVolumeFormat(d.getFormat()))).append("\"");
|
||||
sb.append(" ovf:volume-type=\"").append(escapeAttr(mapVolumeType(d.getSparse()))).append("\"");
|
||||
sb.append(" ovf:disk-interface=\"").append(escapeAttr(diskInterface)).append("\"");
|
||||
sb.append(" ovf:read-only=\"").append(escapeAttr(booleanString(da.getReadOnly(), "false"))).append("\"");
|
||||
sb.append(" ovf:shareable=\"").append(escapeAttr(booleanString(d.getShareable(), "false"))).append("\"");
|
||||
sb.append(" ovf:boot=\"").append(escapeAttr(booleanString(da.getBootable(), "false"))).append("\"");
|
||||
sb.append(" ovf:pass-discard=\"").append(escapeAttr(booleanString(da.getPassDiscard(), "false"))).append("\"");
|
||||
sb.append(" ovf:incremental-backup=\"false\"");
|
||||
sb.append(" ovf:disk-alias=\"").append(escapeAttr(defaultString(d.getAlias()))).append("\"");
|
||||
sb.append(" ovf:disk-description=\"").append(escapeAttr(defaultString(d.getDescription()))).append("\"");
|
||||
sb.append(" ovf:wipe-after-delete=\"").append(escapeAttr(booleanString(d.getWipeAfterDelete(), "false"))).append("\"");
|
||||
sb.append("></Disk>");
|
||||
}
|
||||
sb.append("</Section>");
|
||||
|
||||
// --- Content / VirtualSystem ---
|
||||
sb.append("<Content ovf:id=\"out\" xsi:type=\"ovf:VirtualSystem_Type\">");
|
||||
sb.append("<Name>").append(escapeText(vmName)).append("</Name>");
|
||||
sb.append("<Description>").append(escapeText(vmDesc)).append("</Description>");
|
||||
sb.append("<Comment></Comment>");
|
||||
sb.append("<CreationDate>").append(creationDate).append("</CreationDate>");
|
||||
sb.append("<ExportDate>").append(exportDate).append("</ExportDate>");
|
||||
sb.append("<DeleteProtected>false</DeleteProtected>");
|
||||
sb.append("<SsoMethod>guest_agent</SsoMethod>");
|
||||
sb.append("<IsSmartcardEnabled>false</IsSmartcardEnabled>");
|
||||
sb.append("<NumOfIoThreads>1</NumOfIoThreads>");
|
||||
sb.append("<TimeZone>Etc/GMT</TimeZone>");
|
||||
sb.append("<default_boot_sequence>0</default_boot_sequence>");
|
||||
sb.append("<Generation>11</Generation>");
|
||||
sb.append("<ClusterCompatibilityVersion>4.8</ClusterCompatibilityVersion>");
|
||||
sb.append("<VmType>1</VmType>");
|
||||
sb.append("<ResumeBehavior>AUTO_RESUME</ResumeBehavior>");
|
||||
sb.append("<MinAllocatedMem>").append(memMb).append("</MinAllocatedMem>");
|
||||
sb.append("<IsStateless>").append(escapeText(booleanString(vm.getStateless(), "false"))).append("</IsStateless>");
|
||||
sb.append("<IsRunAndPause>false</IsRunAndPause>");
|
||||
sb.append("<AutoStartup>false</AutoStartup>");
|
||||
sb.append("<Priority>0</Priority>");
|
||||
sb.append("<CreatedByUserId>").append(ZERO_UUID).append("</CreatedByUserId>");
|
||||
sb.append("<MigrationSupport>0</MigrationSupport>");
|
||||
sb.append("<IsBootMenuEnabled>").append(escapeText(booleanString(vm.getBios() != null && vm.getBios().getBootMenu() != null ? vm.getBios().getBootMenu().getEnabled() : null, "false"))).append("</IsBootMenuEnabled>");
|
||||
sb.append("<IsSpiceFileTransferEnabled>true</IsSpiceFileTransferEnabled>");
|
||||
sb.append("<IsSpiceCopyPasteEnabled>true</IsSpiceCopyPasteEnabled>");
|
||||
sb.append("<AllowConsoleReconnect>false</AllowConsoleReconnect>");
|
||||
sb.append("<ConsoleDisconnectAction>LOCK_SCREEN</ConsoleDisconnectAction>");
|
||||
sb.append("<ConsoleDisconnectActionDelay>0</ConsoleDisconnectActionDelay>");
|
||||
sb.append("<CustomEmulatedMachine></CustomEmulatedMachine>");
|
||||
sb.append("<BiosType>").append(mapBiosType(vm.getBios() != null ? vm.getBios().getType() : null)).append("</BiosType>");
|
||||
sb.append("<CustomCpuName></CustomCpuName>");
|
||||
sb.append("<PredefinedProperties></PredefinedProperties>");
|
||||
sb.append("<UserDefinedProperties></UserDefinedProperties>");
|
||||
sb.append("<MaxMemorySizeMb>").append(memMb).append("</MaxMemorySizeMb>");
|
||||
sb.append("<MultiQueuesEnabled>true</MultiQueuesEnabled>");
|
||||
sb.append("<VirtioScsiMultiQueuesEnabled>false</VirtioScsiMultiQueuesEnabled>");
|
||||
sb.append("<UseHostCpu>false</UseHostCpu>");
|
||||
sb.append("<BalloonEnabled>").append(mapBalloonEnabled(vm)).append("</BalloonEnabled>");
|
||||
sb.append("<CpuPinningPolicy>0</CpuPinningPolicy>");
|
||||
sb.append("<ClusterName></ClusterName>");
|
||||
sb.append("<TemplateId>").append(escapeText(templateId)).append("</TemplateId>");
|
||||
sb.append("<TemplateName>").append(escapeText(templateName)).append("</TemplateName>");
|
||||
sb.append("<IsInitilized>true</IsInitilized>");
|
||||
sb.append("<Origin>3</Origin>");
|
||||
sb.append("<quota_id>").append(ZERO_UUID).append("</quota_id>");
|
||||
sb.append("<DefaultDisplayType>2</DefaultDisplayType>");
|
||||
sb.append("<TrustedService>false</TrustedService>");
|
||||
sb.append("<OriginalTemplateId>").append(escapeText(templateId)).append("</OriginalTemplateId>");
|
||||
sb.append("<OriginalTemplateName>").append(escapeText(templateName)).append("</OriginalTemplateName>");
|
||||
sb.append("<UseLatestVersion>false</UseLatestVersion>");
|
||||
sb.append("<StopTime>").append(stopTime).append("</StopTime>");
|
||||
sb.append("<BootTime>").append(bootTime).append("</BootTime>");
|
||||
sb.append("<Downtime>0</Downtime>");
|
||||
|
||||
// --- Operating system section ---
|
||||
sb.append("<Section ovf:id=\"").append(escapeAttr(vmId)).append("\" ovf:required=\"false\" xsi:type=\"ovf:OperatingSystemSection_Type\">");
|
||||
sb.append("<Info>Guest Operating System</Info>");
|
||||
sb.append("<Description>").append(escapeText(inferOsDescription(vm))).append("</Description>");
|
||||
sb.append("</Section>");
|
||||
|
||||
// --- Virtual hardware section ---
|
||||
sb.append("<Section xsi:type=\"ovf:VirtualHardwareSection_Type\">");
|
||||
sb.append("<Info>").append(vcpu).append(" CPU, ").append(memMb).append(" Memory</Info>");
|
||||
sb.append("<System>");
|
||||
sb.append("<vssd:VirtualSystemType>ENGINE 4.4.0.0</vssd:VirtualSystemType>");
|
||||
sb.append("</System>");
|
||||
|
||||
// CPU
|
||||
sb.append("<Item>");
|
||||
sb.append("<rasd:Caption>").append(vcpu).append(" virtual cpu</rasd:Caption>");
|
||||
sb.append("<rasd:Description>Number of virtual CPU</rasd:Description>");
|
||||
sb.append("<rasd:InstanceId>1</rasd:InstanceId>");
|
||||
sb.append("<rasd:ResourceType>3</rasd:ResourceType>");
|
||||
sb.append("<rasd:num_of_sockets>").append(sockets).append("</rasd:num_of_sockets>");
|
||||
sb.append("<rasd:cpu_per_socket>").append(cpuPerSocket).append("</rasd:cpu_per_socket>");
|
||||
sb.append("<rasd:threads_per_cpu>").append(threads).append("</rasd:threads_per_cpu>");
|
||||
sb.append("<rasd:max_num_of_vcpus>").append(maxVcpu).append("</rasd:max_num_of_vcpus>");
|
||||
sb.append("<rasd:VirtualQuantity>").append(vcpu).append("</rasd:VirtualQuantity>");
|
||||
sb.append("</Item>");
|
||||
|
||||
// Memory
|
||||
sb.append("<Item>");
|
||||
sb.append("<rasd:Caption>").append(memMb).append(" MB of memory</rasd:Caption>");
|
||||
sb.append("<rasd:Description>Memory Size</rasd:Description>");
|
||||
sb.append("<rasd:InstanceId>2</rasd:InstanceId>");
|
||||
sb.append("<rasd:ResourceType>4</rasd:ResourceType>");
|
||||
sb.append("<rasd:AllocationUnits>MegaBytes</rasd:AllocationUnits>");
|
||||
sb.append("<rasd:VirtualQuantity>").append(memMb).append("</rasd:VirtualQuantity>");
|
||||
sb.append("</Item>");
|
||||
|
||||
// Disks as Items
|
||||
int diskUnit = 0;
|
||||
for (DiskAttachment da : diskAttachments(vm)) {
|
||||
if (da == null || da.getDisk() == null || StringUtils.isBlank(da.getDisk().getId())) {
|
||||
continue;
|
||||
}
|
||||
final org.apache.cloudstack.veeam.api.dto.Disk d = da.getDisk();
|
||||
final String diskId = d.getId();
|
||||
final String storageDomainId = firstStorageDomainId(d);
|
||||
final String href = storageDomainId + "/" + diskId;
|
||||
|
||||
sb.append("<Item>");
|
||||
sb.append("<rasd:Caption>").append(escapeText(defaultString(d.getAlias()))).append("</rasd:Caption>");
|
||||
sb.append("<rasd:InstanceId>").append(escapeText(diskId)).append("</rasd:InstanceId>");
|
||||
sb.append("<rasd:ResourceType>17</rasd:ResourceType>");
|
||||
sb.append("<rasd:HostResource>").append(escapeText(href)).append("</rasd:HostResource>");
|
||||
sb.append("<rasd:Parent>").append(ZERO_UUID).append("</rasd:Parent>");
|
||||
sb.append("<rasd:Template>").append(escapeText(templateId)).append("</rasd:Template>");
|
||||
sb.append("<rasd:ApplicationList></rasd:ApplicationList>");
|
||||
sb.append("<rasd:StorageId>").append(escapeText(storageDomainId)).append("</rasd:StorageId>");
|
||||
sb.append("<rasd:StoragePoolId>").append(ZERO_UUID).append("</rasd:StoragePoolId>");
|
||||
sb.append("<rasd:CreationDate>").append(creationDate).append("</rasd:CreationDate>");
|
||||
sb.append("<rasd:LastModified>").append(exportDate).append("</rasd:LastModified>");
|
||||
sb.append("<rasd:last_modified_date>").append(exportDate).append("</rasd:last_modified_date>");
|
||||
sb.append("<Type>disk</Type>");
|
||||
sb.append("<Device>disk</Device>");
|
||||
sb.append("<rasd:Address>").append(escapeText("{type=drive, bus=0, controller=0, target=0, unit=" + diskUnit + "}")).append("</rasd:Address>");
|
||||
sb.append("<BootOrder>").append("true".equalsIgnoreCase(da.getBootable()) ? 1 : 0).append("</BootOrder>");
|
||||
sb.append("<IsPlugged>true</IsPlugged>");
|
||||
sb.append("<IsReadOnly>").append("true".equalsIgnoreCase(da.getReadOnly())).append("</IsReadOnly>");
|
||||
sb.append("<Alias>").append(escapeText("ua-" + href)).append("</Alias>");
|
||||
sb.append("</Item>");
|
||||
diskUnit++;
|
||||
}
|
||||
|
||||
// NICs as Items
|
||||
int nicSlot = 0;
|
||||
for (Nic nic : nics(vm)) {
|
||||
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()) : "";
|
||||
|
||||
sb.append("<Item>");
|
||||
sb.append("<rasd:Caption>Ethernet adapter on [No Network]</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>");
|
||||
sb.append("<rasd:ResourceSubType>").append(mapNicResourceSubType(nic.getInterfaceType())).append("</rasd:ResourceSubType>");
|
||||
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:MACAddress>").append(escapeText(mac)).append("</rasd:MACAddress>");
|
||||
sb.append("<rasd:speed>10000</rasd:speed>");
|
||||
sb.append("<Type>interface</Type>");
|
||||
sb.append("<Device>bridge</Device>");
|
||||
sb.append("<rasd:Address>").append(escapeText("{type=pci, slot=0x" + String.format("%02x", nicSlot) + ", bus=0x01, domain=0x0000, function=0x0}")).append("</rasd:Address>");
|
||||
sb.append("<BootOrder>0</BootOrder>");
|
||||
sb.append("<IsPlugged>").append(escapeText(booleanString(nic.getPlugged(), "true"))).append("</IsPlugged>");
|
||||
sb.append("<IsReadOnly>false</IsReadOnly>");
|
||||
sb.append("<Alias>").append(escapeText("ua-" + nicId)).append("</Alias>");
|
||||
sb.append("</Item>");
|
||||
nicSlot++;
|
||||
}
|
||||
|
||||
// A few common devices that some consumers expect to exist (kept minimal)
|
||||
// USB controller
|
||||
sb.append("<Item>");
|
||||
sb.append("<rasd:Caption>USB Controller</rasd:Caption>");
|
||||
sb.append("<rasd:InstanceId>3</rasd:InstanceId>");
|
||||
sb.append("<rasd:ResourceType>23</rasd:ResourceType>");
|
||||
sb.append("<rasd:UsbPolicy>DISABLED</rasd:UsbPolicy>");
|
||||
sb.append("</Item>");
|
||||
|
||||
// RNG device
|
||||
sb.append("<Item>");
|
||||
sb.append("<rasd:ResourceType>0</rasd:ResourceType>");
|
||||
sb.append("<rasd:InstanceId>").append(UUID.nameUUIDFromBytes(("rng-" + vmId).getBytes(StandardCharsets.UTF_8))).append("</rasd:InstanceId>");
|
||||
sb.append("<Type>rng</Type>");
|
||||
sb.append("<Device>virtio</Device>");
|
||||
sb.append("<rasd:Address>{type=pci, slot=0x00, bus=0x06, domain=0x0000, function=0x0}</rasd:Address>");
|
||||
sb.append("<BootOrder>0</BootOrder>");
|
||||
sb.append("<IsPlugged>true</IsPlugged>");
|
||||
sb.append("<IsReadOnly>false</IsReadOnly>");
|
||||
sb.append("<Alias></Alias>");
|
||||
sb.append("<SpecParams><source>urandom</source></SpecParams>");
|
||||
sb.append("</Item>");
|
||||
|
||||
sb.append("</Content>");
|
||||
sb.append("</ovf:Envelope>");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void updateFromConfiguration(Vm vm) {
|
||||
if (ObjectUtils.anyNull(vm.getInitialization(),
|
||||
vm.getInitialization().getConfiguration(),
|
||||
vm.getInitialization().getConfiguration().getData())) {
|
||||
return;
|
||||
}
|
||||
OvfXmlUtil.updateFromXml(vm, vm.getInitialization().getConfiguration().getData());
|
||||
}
|
||||
|
||||
protected static void updateFromXml(Vm vm, String ovfXml) {
|
||||
if (vm == null || StringUtils.isBlank(ovfXml)) {
|
||||
return;
|
||||
}
|
||||
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(ovfXml.getBytes(StandardCharsets.UTF_8)));
|
||||
|
||||
XPathFactory xpf = XPathFactory.newInstance();
|
||||
XPath xpath = xpf.newXPath();
|
||||
|
||||
// Register namespace context for XPath
|
||||
xpath.setNamespaceContext(new OvfNamespaceContext());
|
||||
|
||||
Node hwSection = (Node) xpath.evaluate(
|
||||
"//*[local-name()='Section' and @*[local-name()='type']='ovf:VirtualHardwareSection_Type']",
|
||||
doc,
|
||||
XPathConstants.NODE
|
||||
);
|
||||
|
||||
if (hwSection != null) {
|
||||
// Memory
|
||||
NodeList memItems = (NodeList) xpath.evaluate(
|
||||
".//*[local-name()='Item'][*[local-name()='ResourceType' and text()='4']]",
|
||||
hwSection,
|
||||
XPathConstants.NODESET
|
||||
);
|
||||
if (memItems != null && memItems.getLength() > 0) {
|
||||
Node memItem = memItems.item(0);
|
||||
String memStr = childText(memItem, "VirtualQuantity");
|
||||
if (StringUtils.isNotBlank(memStr)) {
|
||||
vm.setMemory(memStr);
|
||||
}
|
||||
}
|
||||
|
||||
// CPU
|
||||
NodeList cpuItems = (NodeList) xpath.evaluate(
|
||||
".//*[local-name()='Item'][*[local-name()='ResourceType' and text()='3']]",
|
||||
hwSection,
|
||||
XPathConstants.NODESET
|
||||
);
|
||||
if (cpuItems != null && cpuItems.getLength() > 0) {
|
||||
Node cpuItem = cpuItems.item(0);
|
||||
String socketsStr = childText(cpuItem, "num_of_sockets");
|
||||
String coresStr = childText(cpuItem, "cpu_per_socket");
|
||||
String threadsStr = childText(cpuItem, "threads_per_cpu");
|
||||
|
||||
if (vm.getCpu() == null) {
|
||||
vm.setCpu(new Cpu());
|
||||
}
|
||||
if (vm.getCpu().getTopology() == null) {
|
||||
vm.getCpu().setTopology(new Topology());
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(socketsStr)) {
|
||||
vm.getCpu().getTopology().setSockets(socketsStr);
|
||||
}
|
||||
if (StringUtils.isNotBlank(coresStr)) {
|
||||
vm.getCpu().getTopology().setCores(coresStr);
|
||||
}
|
||||
if (StringUtils.isNotBlank(threadsStr)) {
|
||||
vm.getCpu().getTopology().setThreads(threadsStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Ignore parsing errors and keep original VM configuration
|
||||
}
|
||||
}
|
||||
|
||||
private static String xpathString(XPath xpath, Document doc, String expression) {
|
||||
try {
|
||||
String value = (String) xpath.evaluate(expression, doc, XPathConstants.STRING);
|
||||
return StringUtils.isBlank(value) ? null : value.trim();
|
||||
} catch (XPathExpressionException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String childText(Node parent, String localName) {
|
||||
if (parent == null || StringUtils.isBlank(localName)) {
|
||||
return null;
|
||||
}
|
||||
NodeList children = parent.getChildNodes();
|
||||
for (int i = 0; i < children.getLength(); i++) {
|
||||
Node child = children.item(i);
|
||||
if (child.getNodeType() != Node.ELEMENT_NODE) {
|
||||
continue;
|
||||
}
|
||||
String ln = child.getLocalName();
|
||||
if (StringUtils.isBlank(ln)) {
|
||||
ln = child.getNodeName();
|
||||
}
|
||||
if (localName.equalsIgnoreCase(ln)) {
|
||||
return StringUtils.trim(child.getTextContent());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static List<DiskAttachment> diskAttachments(Vm vm) {
|
||||
if (vm.getDiskAttachments() == null) {
|
||||
return List.of();
|
||||
}
|
||||
return vm.getDiskAttachments().getItems();
|
||||
}
|
||||
|
||||
private static List<Nic> nics(Vm vm) {
|
||||
if (vm.getNics() == null) {
|
||||
return List.of();
|
||||
}
|
||||
return vm.getNics().getItems();
|
||||
}
|
||||
|
||||
private static String inferOsDescription(Vm vm) {
|
||||
if (vm.getOs() == null) {
|
||||
return "other";
|
||||
}
|
||||
String t = vm.getOs().getType();
|
||||
if (StringUtils.isBlank(t)) {
|
||||
return "other";
|
||||
}
|
||||
if (t.toLowerCase(Locale.ROOT).contains("win")) {
|
||||
return "windows";
|
||||
}
|
||||
if (t.toLowerCase(Locale.ROOT).contains("linux")) {
|
||||
return "linux";
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
private static String inferNetworkName(Nic nic) {
|
||||
return "Network-" + nic.getId();
|
||||
}
|
||||
|
||||
private static String firstStorageDomainId(Disk d) {
|
||||
if (ObjectUtils.allNotNull(d, d.getStorageDomains()) && CollectionUtils.isNotEmpty(d.getStorageDomains().getItems())) {
|
||||
return d.getStorageDomains().getItems().get(0).getId();
|
||||
}
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
private static String mapDiskInterface(String iface) {
|
||||
if (StringUtils.isBlank(iface)) {
|
||||
return "VirtIO_SCSI";
|
||||
}
|
||||
String v = iface.toLowerCase(Locale.ROOT);
|
||||
if (v.contains("virtio") && v.contains("scsi")) {
|
||||
return "VirtIO_SCSI";
|
||||
}
|
||||
if (v.contains("virtio")) {
|
||||
return "VirtIO";
|
||||
}
|
||||
if (v.contains("ide")) {
|
||||
return "IDE";
|
||||
}
|
||||
if (v.contains("sata")) {
|
||||
return "SATA";
|
||||
}
|
||||
return iface;
|
||||
}
|
||||
|
||||
private static String mapOvfDiskFormat(String format, String sparse) {
|
||||
if ("true".equalsIgnoreCase(sparse)) {
|
||||
return "http://www.vmware.com/specifications/vmdk.html#sparse";
|
||||
}
|
||||
return "http://www.vmware.com/specifications/vmdk.html#sparse";
|
||||
}
|
||||
|
||||
private static String mapVolumeFormat(String format) {
|
||||
if (StringUtils.isBlank(format)) {
|
||||
return "RAW";
|
||||
}
|
||||
String f = format.toLowerCase(Locale.ROOT);
|
||||
if (f.contains("cow") || f.contains("qcow")) {
|
||||
return "COW";
|
||||
}
|
||||
if (f.contains("raw")) {
|
||||
return "RAW";
|
||||
}
|
||||
return format.toUpperCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
private static String mapVolumeType(String sparse) {
|
||||
return "true".equalsIgnoreCase(sparse) ? "Sparse" : "Preallocated";
|
||||
}
|
||||
|
||||
private static int mapBiosType(String biosType) {
|
||||
if (StringUtils.isBlank(biosType)) {
|
||||
return 2;
|
||||
}
|
||||
String t = biosType.toLowerCase(Locale.ROOT);
|
||||
if (t.contains("uefi") || t.contains("secure")) {
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static String mapBalloonEnabled(Vm vm) {
|
||||
if (vm.getMemoryPolicy() == null || vm.getMemoryPolicy().getBallooning() == null) {
|
||||
return "true";
|
||||
}
|
||||
return "true".equalsIgnoreCase(vm.getMemoryPolicy().getBallooning()) ? "true" : "false";
|
||||
}
|
||||
|
||||
private static int mapNicResourceSubType(String iface) {
|
||||
if (StringUtils.isBlank(iface)) {
|
||||
return 3;
|
||||
}
|
||||
String v = iface.toLowerCase(Locale.ROOT);
|
||||
if (v.contains("virtio")) {
|
||||
return 3;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
private static String booleanString(String v, String def) {
|
||||
if (StringUtils.isBlank(v)) {
|
||||
return def;
|
||||
}
|
||||
if ("true".equalsIgnoreCase(v)) {
|
||||
return "true";
|
||||
}
|
||||
if ("false".equalsIgnoreCase(v)) {
|
||||
return "false";
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
private static String firstNonBlank(String... vals) {
|
||||
for (String v : vals) {
|
||||
if (StringUtils.isNotBlank(v)) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String defaultString(String s) {
|
||||
return s == null ? "" : s;
|
||||
}
|
||||
|
||||
private static long parseLong(String s, long def) {
|
||||
if (StringUtils.isBlank(s)) {
|
||||
return def;
|
||||
}
|
||||
try {
|
||||
return Long.parseLong(s);
|
||||
} catch (Exception ignored) {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
private static long bytesToGibCeil(long bytes) {
|
||||
if (bytes <= 0) {
|
||||
return 0;
|
||||
}
|
||||
final long gib = 1024L * 1024L * 1024L;
|
||||
return (bytes + gib - 1) / gib;
|
||||
}
|
||||
|
||||
private static String formatDate(long epochMillis) {
|
||||
return OVIRT_DTF.get().format(new Date(epochMillis));
|
||||
}
|
||||
|
||||
private static String escapeText(String s) {
|
||||
if (s == null) {
|
||||
return "";
|
||||
}
|
||||
return s.replace("&", "&")
|
||||
.replace("<", "<")
|
||||
.replace(">", ">")
|
||||
.replace("\"", """)
|
||||
.replace("'", "'");
|
||||
}
|
||||
|
||||
private static String escapeAttr(String s) {
|
||||
return escapeText(s);
|
||||
}
|
||||
|
||||
protected static class OvfNamespaceContext implements NamespaceContext {
|
||||
@Override
|
||||
public String getNamespaceURI(String prefix) {
|
||||
if ("ovf".equals(prefix)) return NS_OVF;
|
||||
if ("rasd".equals(prefix)) return NS_RASD;
|
||||
if ("vssd".equals(prefix)) return NS_VSSD;
|
||||
if ("xsi".equals(prefix)) return NS_XSI;
|
||||
return XMLConstants.NULL_NS_URI;
|
||||
}
|
||||
@Override
|
||||
public String getPrefix(String namespaceURI) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public java.util.Iterator<String> getPrefixes(String namespaceURI) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -17,27 +17,41 @@
|
|||
|
||||
package org.apache.cloudstack.veeam.api.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
public class Tag extends BaseDto {
|
||||
private String name;
|
||||
private String description;
|
||||
private Ref parent;
|
||||
private Ref vm;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public final class Bios {
|
||||
|
||||
private String type; // "uefi" or "bios" or whatever mapping you choose
|
||||
private BootMenu bootMenu = new BootMenu();
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public BootMenu getBootMenu() {
|
||||
return bootMenu;
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setBootMenu(BootMenu bootMenu) {
|
||||
this.bootMenu = bootMenu;
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Ref getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public void setParent(Ref parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public Ref getVm() {
|
||||
return vm;
|
||||
}
|
||||
|
||||
public void setVm(Ref vm) {
|
||||
this.vm = vm;
|
||||
}
|
||||
}
|
||||
|
|
@ -42,6 +42,7 @@ public final class Vm extends BaseDto {
|
|||
private Ref cluster;
|
||||
private Ref host;
|
||||
private String memory; // bytes
|
||||
private MemoryPolicy memoryPolicy;
|
||||
private Cpu cpu;
|
||||
private Os os;
|
||||
private Bios bios;
|
||||
|
|
@ -53,8 +54,22 @@ public final class Vm extends BaseDto {
|
|||
private List<Link> link; // related resources
|
||||
private EmptyElement tags; // empty <tags/>
|
||||
private NamedList<DiskAttachment> diskAttachments;
|
||||
private Nics nics;
|
||||
private VmInitialization initialization;
|
||||
private NamedList<Nic> nics;
|
||||
private Initialization initialization;
|
||||
|
||||
private Ref cpuProfile;
|
||||
|
||||
public EmptyElement io = new EmptyElement();
|
||||
public EmptyElement migration = new EmptyElement();
|
||||
public EmptyElement sso = new EmptyElement();
|
||||
public EmptyElement usb = new EmptyElement();
|
||||
public EmptyElement quota = new EmptyElement();
|
||||
public EmptyElement highAvailability = new EmptyElement();
|
||||
public EmptyElement largeIcon = new EmptyElement();
|
||||
public EmptyElement smallIcon = new EmptyElement();
|
||||
public EmptyElement placementPolicy = new EmptyElement();
|
||||
public EmptyElement timeZone = new EmptyElement();
|
||||
public EmptyElement display = new EmptyElement();
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
|
|
@ -152,6 +167,14 @@ public final class Vm extends BaseDto {
|
|||
this.memory = memory;
|
||||
}
|
||||
|
||||
public MemoryPolicy getMemoryPolicy() {
|
||||
return memoryPolicy;
|
||||
}
|
||||
|
||||
public void setMemoryPolicy(MemoryPolicy memoryPolicy) {
|
||||
this.memoryPolicy = memoryPolicy;
|
||||
}
|
||||
|
||||
public Cpu getCpu() {
|
||||
return cpu;
|
||||
}
|
||||
|
|
@ -232,22 +255,145 @@ public final class Vm extends BaseDto {
|
|||
this.diskAttachments = diskAttachments;
|
||||
}
|
||||
|
||||
public Nics getNics() {
|
||||
public NamedList<Nic> getNics() {
|
||||
return nics;
|
||||
}
|
||||
|
||||
public void setNics(Nics nics) {
|
||||
public void setNics(NamedList<Nic> nics) {
|
||||
this.nics = nics;
|
||||
}
|
||||
|
||||
public VmInitialization getInitialization() {
|
||||
public Initialization getInitialization() {
|
||||
return initialization;
|
||||
}
|
||||
|
||||
public void setInitialization(VmInitialization initialization) {
|
||||
public void setInitialization(Initialization initialization) {
|
||||
this.initialization = initialization;
|
||||
}
|
||||
|
||||
public Ref getCpuProfile() {
|
||||
return cpuProfile;
|
||||
}
|
||||
|
||||
public void setCpuProfile(Ref cpuProfile) {
|
||||
this.cpuProfile = cpuProfile;
|
||||
}
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public static final class Bios {
|
||||
|
||||
private String type; // "uefi" or "bios" or whatever mapping you choose
|
||||
private BootMenu bootMenu = new BootMenu();
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public BootMenu getBootMenu() {
|
||||
return bootMenu;
|
||||
}
|
||||
|
||||
public void setBootMenu(BootMenu bootMenu) {
|
||||
this.bootMenu = bootMenu;
|
||||
}
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public static class BootMenu {
|
||||
|
||||
private String enabled;
|
||||
|
||||
public String getEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(String enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public static final class MemoryPolicy {
|
||||
|
||||
private String guaranteed;
|
||||
private String max;
|
||||
private String ballooning;
|
||||
|
||||
public String getGuaranteed() {
|
||||
return guaranteed;
|
||||
}
|
||||
|
||||
public void setGuaranteed(String guaranteed) {
|
||||
this.guaranteed = guaranteed;
|
||||
}
|
||||
|
||||
public String getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
public void setMax(String max) {
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public String getBallooning() {
|
||||
return ballooning;
|
||||
}
|
||||
|
||||
public void setBallooning(String ballooning) {
|
||||
this.ballooning = ballooning;
|
||||
}
|
||||
}
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public static class Initialization {
|
||||
|
||||
private String customScript;
|
||||
private Configuration configuration;
|
||||
|
||||
public String getCustomScript() {
|
||||
return customScript;
|
||||
}
|
||||
|
||||
public void setCustomScript(String customScript) {
|
||||
this.customScript = customScript;
|
||||
}
|
||||
|
||||
public Configuration getConfiguration() {
|
||||
return configuration;
|
||||
}
|
||||
|
||||
public void setConfiguration(Configuration configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public static class Configuration {
|
||||
|
||||
private String data;
|
||||
private String type;
|
||||
|
||||
public String getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(String data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Vm of(String href, String id) {
|
||||
Vm vm = new Vm();
|
||||
vm.setHref(href);
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.veeam.api.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class VmInitialization {
|
||||
|
||||
private String customScript;
|
||||
|
||||
public String getCustomScript() {
|
||||
return customScript;
|
||||
}
|
||||
|
||||
public void setCustomScript(String customScript) {
|
||||
this.customScript = customScript;
|
||||
}
|
||||
}
|
||||
|
|
@ -43,6 +43,7 @@
|
|||
<bean id="disksRouteHandler" class="org.apache.cloudstack.veeam.api.DisksRouteHandler"/>
|
||||
<bean id="imageTransfersRouteHandler" class="org.apache.cloudstack.veeam.api.ImageTransfersRouteHandler"/>
|
||||
<bean id="jobsRouteHandler" class="org.apache.cloudstack.veeam.api.JobsRouteHandler"/>
|
||||
<bean id="tagsRouteHandler" class="org.apache.cloudstack.veeam.api.TagsRouteHandler"/>
|
||||
|
||||
<bean id="veeamControlService" class="org.apache.cloudstack.veeam.VeeamControlServiceImpl" >
|
||||
<property name="routeHandlers" value="#{routeHandlerRegistry.registered}" />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,618 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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="ddf18375-4c69-4ec5-8371-6dabc94e4e60/5cbc2ed5-de89-44a4-aa58-b7161f8afaf8" ovf:id="5cbc2ed5-de89-44a4-aa58-b7161f8afaf8" ovf:size="4096" ovf:description="Active VM" ovf:disk_storage_type="IMAGE" ovf:cinder_volume_type=""></File>
|
||||
</References>
|
||||
<NetworkSection>
|
||||
<Info>List of networks</Info>
|
||||
</NetworkSection>
|
||||
<Section xsi:type="ovf:DiskSection_Type">
|
||||
<Info>List of Virtual Disks</Info>
|
||||
<Disk ovf:diskId="5cbc2ed5-de89-44a4-aa58-b7161f8afaf8" ovf:size="1" ovf:actual_size="1" ovf:vm_snapshot_id="3d298647-57d5-4a2b-90e7-226bdb4f1800" ovf:parentRef="" ovf:fileRef="ddf18375-4c69-4ec5-8371-6dabc94e4e60/5cbc2ed5-de89-44a4-aa58-b7161f8afaf8" ovf:format="http://www.vmware.com/specifications/vmdk.html#sparse" ovf:volume-format="RAW" 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="test-vm-abhisar_Disk1" ovf:disk-description="" ovf:wipe-after-delete="false"></Disk>
|
||||
</Section>
|
||||
<Content ovf:id="out" xsi:type="ovf:VirtualSystem_Type">
|
||||
<Name>test-vm-abhisar</Name>
|
||||
<Description></Description>
|
||||
<Comment></Comment>
|
||||
<CreationDate>2026/01/07 13:37:09</CreationDate>
|
||||
<ExportDate>2026/01/08 04:07:00</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>1024</MinAllocatedMem>
|
||||
<IsStateless>false</IsStateless>
|
||||
<IsRunAndPause>false</IsRunAndPause>
|
||||
<AutoStartup>false</AutoStartup>
|
||||
<Priority>0</Priority>
|
||||
<CreatedByUserId>c067a148-e4d5-11f0-98ce-00163e6c35f4</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>2</BiosType>
|
||||
<CustomCpuName></CustomCpuName>
|
||||
<PredefinedProperties></PredefinedProperties>
|
||||
<UserDefinedProperties></UserDefinedProperties>
|
||||
<MaxMemorySizeMb>4096</MaxMemorySizeMb>
|
||||
<MultiQueuesEnabled>true</MultiQueuesEnabled>
|
||||
<VirtioScsiMultiQueuesEnabled>false</VirtioScsiMultiQueuesEnabled>
|
||||
<UseHostCpu>false</UseHostCpu>
|
||||
<BalloonEnabled>true</BalloonEnabled>
|
||||
<CpuPinningPolicy>0</CpuPinningPolicy>
|
||||
<ClusterName>Default</ClusterName>
|
||||
<TemplateId>00000000-0000-0000-0000-000000000000</TemplateId>
|
||||
<TemplateName>Blank</TemplateName>
|
||||
<IsInitilized>true</IsInitilized>
|
||||
<Origin>3</Origin>
|
||||
<quota_id>95e46398-e4d5-11f0-bb71-00163e6c35f4</quota_id>
|
||||
<DefaultDisplayType>2</DefaultDisplayType>
|
||||
<TrustedService>false</TrustedService>
|
||||
<OriginalTemplateId>00000000-0000-0000-0000-000000000000</OriginalTemplateId>
|
||||
<OriginalTemplateName>Blank</OriginalTemplateName>
|
||||
<UseLatestVersion>false</UseLatestVersion>
|
||||
<StopTime>2026/01/07 13:37:09</StopTime>
|
||||
<BootTime>2026/01/07 13:38:03</BootTime>
|
||||
<Downtime>0</Downtime>
|
||||
<Section ovf:id="9ce5bba0-6e01-4467-95a1-c4e28ad3ea43" ovf:required="false" xsi:type="ovf:OperatingSystemSection_Type">
|
||||
<Info>Guest Operating System</Info>
|
||||
<Description>other</Description>
|
||||
</Section>
|
||||
<Section xsi:type="ovf:VirtualHardwareSection_Type">
|
||||
<Info>1 CPU, 1024 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>16</rasd:max_num_of_vcpus>
|
||||
<rasd:VirtualQuantity>1</rasd:VirtualQuantity>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:Caption>1024 MB of memory</rasd:Caption>
|
||||
<rasd:Description>Memory Size</rasd:Description>
|
||||
<rasd:InstanceId>2</rasd:InstanceId>
|
||||
<rasd:ResourceType>4</rasd:ResourceType>
|
||||
<rasd:AllocationUnits>MegaBytes</rasd:AllocationUnits>
|
||||
<rasd:VirtualQuantity>1024</rasd:VirtualQuantity>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:Caption>test-vm-abhisar_Disk1</rasd:Caption>
|
||||
<rasd:InstanceId>5cbc2ed5-de89-44a4-aa58-b7161f8afaf8</rasd:InstanceId>
|
||||
<rasd:ResourceType>17</rasd:ResourceType>
|
||||
<rasd:HostResource>ddf18375-4c69-4ec5-8371-6dabc94e4e60/5cbc2ed5-de89-44a4-aa58-b7161f8afaf8</rasd:HostResource>
|
||||
<rasd:Parent>00000000-0000-0000-0000-000000000000</rasd:Parent>
|
||||
<rasd:Template>00000000-0000-0000-0000-000000000000</rasd:Template>
|
||||
<rasd:ApplicationList></rasd:ApplicationList>
|
||||
<rasd:StorageId>41609681-c92a-410a-bcc2-5b5e1305cdd1</rasd:StorageId>
|
||||
<rasd:StoragePoolId>91f4d826-e4d5-11f0-bd93-00163e6c35f4</rasd:StoragePoolId>
|
||||
<rasd:CreationDate>2026/01/07 13:36:59</rasd:CreationDate>
|
||||
<rasd:LastModified>2026/01/07 13:53:36</rasd:LastModified>
|
||||
<rasd:last_modified_date>2026/01/08 04:07:00</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-ddf18375-4c69-4ec5-8371-6dabc94e4e60</Alias>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:Caption>Ethernet adapter on [No Network]</rasd:Caption>
|
||||
<rasd:InstanceId>9a6f804d-b305-41db-b1b4-bdfd82c4b446</rasd:InstanceId>
|
||||
<rasd:ResourceType>10</rasd:ResourceType>
|
||||
<rasd:OtherResourceType></rasd:OtherResourceType>
|
||||
<rasd:ResourceSubType>3</rasd:ResourceSubType>
|
||||
<rasd:Connection></rasd:Connection>
|
||||
<rasd:Linked>true</rasd:Linked>
|
||||
<rasd:Name>nic1</rasd:Name>
|
||||
<rasd:ElementName>nic1</rasd:ElementName>
|
||||
<rasd:MACAddress>56:6f:9f:c0:00:07</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-9a6f804d-b305-41db-b1b4-bdfd82c4b446</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:Caption>Graphical Controller</rasd:Caption>
|
||||
<rasd:InstanceId>0d4a490c-f9d7-45dd-8686-69d5bae218d6</rasd:InstanceId>
|
||||
<rasd:ResourceType>20</rasd:ResourceType>
|
||||
<rasd:VirtualQuantity>1</rasd:VirtualQuantity>
|
||||
<rasd:SinglePciQxl>false</rasd:SinglePciQxl>
|
||||
<Type>video</Type>
|
||||
<Device>vga</Device>
|
||||
<rasd:Address>{type=pci, slot=0x01, bus=0x00, domain=0x0000, function=0x0}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>ua-0d4a490c-f9d7-45dd-8686-69d5bae218d6</Alias>
|
||||
<SpecParams>
|
||||
<vram>16384</vram>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:Caption>Graphical Framebuffer</rasd:Caption>
|
||||
<rasd:InstanceId>f62554f1-05fe-472e-a34b-9e6b980ad59f</rasd:InstanceId>
|
||||
<rasd:ResourceType>26</rasd:ResourceType>
|
||||
<Type>graphics</Type>
|
||||
<Device>vnc</Device>
|
||||
<rasd:Address></rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias></Alias>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:Caption>CDROM</rasd:Caption>
|
||||
<rasd:InstanceId>9c38cc6a-9def-46f3-bf1c-2b3f4aa6b764</rasd:InstanceId>
|
||||
<rasd:ResourceType>15</rasd:ResourceType>
|
||||
<Type>disk</Type>
|
||||
<Device>cdrom</Device>
|
||||
<rasd:Address>{type=drive, bus=0, controller=0, target=0, unit=2}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>true</IsReadOnly>
|
||||
<Alias>ua-9c38cc6a-9def-46f3-bf1c-2b3f4aa6b764</Alias>
|
||||
<SpecParams>
|
||||
<path></path>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>a737450e-20b5-427e-a18b-85ec20683e31</rasd:InstanceId>
|
||||
<Type>channel</Type>
|
||||
<Device>unix</Device>
|
||||
<rasd:Address>{type=virtio-serial, bus=0, controller=0, port=1}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>channel0</Alias>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>1d3ba276-9e8d-4a16-9cdf-dfd25180b7bc</rasd:InstanceId>
|
||||
<Type>channel</Type>
|
||||
<Device>unix</Device>
|
||||
<rasd:Address>{type=virtio-serial, bus=0, controller=0, port=2}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>channel1</Alias>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>8f21ce42-9499-4ded-88d4-04dff2fdc3ff</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>pci</Device>
|
||||
<rasd:Address>{type=pci, slot=0x02, bus=0x00, domain=0x0000, function=0x0, multifunction=on}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>pci.1</Alias>
|
||||
<SpecParams>
|
||||
<index>1</index>
|
||||
<model>pcie-root-port</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>d1b9d421-1a57-469d-97fe-0682ad4594c3</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>pci</Device>
|
||||
<rasd:Address>{type=pci, slot=0x02, bus=0x00, domain=0x0000, function=0x1}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>pci.2</Alias>
|
||||
<SpecParams>
|
||||
<index>2</index>
|
||||
<model>pcie-root-port</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>768c4772-eb7a-4f0f-85a7-2b94e20fe78c</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>pci</Device>
|
||||
<rasd:Address>{type=pci, slot=0x02, bus=0x00, domain=0x0000, function=0x2}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>pci.3</Alias>
|
||||
<SpecParams>
|
||||
<index>3</index>
|
||||
<model>pcie-root-port</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>d20bae3b-f5d7-4131-b00a-3cf66f390434</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>pci</Device>
|
||||
<rasd:Address>{type=pci, slot=0x02, bus=0x00, domain=0x0000, function=0x3}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>pci.4</Alias>
|
||||
<SpecParams>
|
||||
<index>4</index>
|
||||
<model>pcie-root-port</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>5887f3ad-c575-488e-9138-fca9c7064ae5</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>pci</Device>
|
||||
<rasd:Address>{type=pci, slot=0x02, bus=0x00, domain=0x0000, function=0x4}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>pci.5</Alias>
|
||||
<SpecParams>
|
||||
<index>5</index>
|
||||
<model>pcie-root-port</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>f880f086-227e-4e25-b2fc-8a3d13d1f1bd</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>pci</Device>
|
||||
<rasd:Address>{type=pci, slot=0x02, bus=0x00, domain=0x0000, function=0x5}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>pci.6</Alias>
|
||||
<SpecParams>
|
||||
<index>6</index>
|
||||
<model>pcie-root-port</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>d64f62a0-6176-482b-8d24-f82fb32b8f12</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>pci</Device>
|
||||
<rasd:Address>{type=pci, slot=0x02, bus=0x00, domain=0x0000, function=0x6}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>pci.7</Alias>
|
||||
<SpecParams>
|
||||
<index>7</index>
|
||||
<model>pcie-root-port</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>1544f32e-1e94-4e10-b198-7c5e95ab280d</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>pci</Device>
|
||||
<rasd:Address>{type=pci, slot=0x02, bus=0x00, domain=0x0000, function=0x7}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>pci.8</Alias>
|
||||
<SpecParams>
|
||||
<index>8</index>
|
||||
<model>pcie-root-port</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>7dd5080f-8c04-4593-8c6a-1dc5cd6c3e3e</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>pci</Device>
|
||||
<rasd:Address>{type=pci, slot=0x03, bus=0x00, domain=0x0000, function=0x0, multifunction=on}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>pci.9</Alias>
|
||||
<SpecParams>
|
||||
<index>9</index>
|
||||
<model>pcie-root-port</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>4dab4257-2729-482c-b4e1-6a3c05161153</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>pci</Device>
|
||||
<rasd:Address>{type=pci, slot=0x03, bus=0x00, domain=0x0000, function=0x1}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>pci.10</Alias>
|
||||
<SpecParams>
|
||||
<index>10</index>
|
||||
<model>pcie-root-port</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>99effa2f-2963-4abd-9eab-1cbe8e913ca4</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>pci</Device>
|
||||
<rasd:Address>{type=pci, slot=0x03, bus=0x00, domain=0x0000, function=0x2}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>pci.11</Alias>
|
||||
<SpecParams>
|
||||
<index>11</index>
|
||||
<model>pcie-root-port</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>2a376983-897b-4396-be32-89f2a9ca7d22</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>pci</Device>
|
||||
<rasd:Address>{type=pci, slot=0x03, bus=0x00, domain=0x0000, function=0x3}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>pci.12</Alias>
|
||||
<SpecParams>
|
||||
<index>12</index>
|
||||
<model>pcie-root-port</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>2e763d82-4475-4268-bc0a-07c915ec19c8</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>pci</Device>
|
||||
<rasd:Address>{type=pci, slot=0x03, bus=0x00, domain=0x0000, function=0x4}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>pci.13</Alias>
|
||||
<SpecParams>
|
||||
<index>13</index>
|
||||
<model>pcie-root-port</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>ef39155f-760e-4374-afb9-ff05cc8b9609</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>pci</Device>
|
||||
<rasd:Address>{type=pci, slot=0x03, bus=0x00, domain=0x0000, function=0x5}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>pci.14</Alias>
|
||||
<SpecParams>
|
||||
<index>14</index>
|
||||
<model>pcie-root-port</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>74be06f0-84b6-472e-a054-486343f66084</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>pci</Device>
|
||||
<rasd:Address>{type=pci, slot=0x03, bus=0x00, domain=0x0000, function=0x6}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>pci.15</Alias>
|
||||
<SpecParams>
|
||||
<index>15</index>
|
||||
<model>pcie-root-port</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>c68db43a-fa3a-4689-941d-b477d2676d27</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>pci</Device>
|
||||
<rasd:Address>{type=pci, slot=0x03, bus=0x00, domain=0x0000, function=0x7}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>pci.16</Alias>
|
||||
<SpecParams>
|
||||
<index>16</index>
|
||||
<model>pcie-root-port</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>d11cbe26-ee82-4e15-b8eb-2aa7b285d00d</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>pci</Device>
|
||||
<rasd:Address>{type=pci, slot=0x04, bus=0x00, domain=0x0000, function=0x0, multifunction=on}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>pci.17</Alias>
|
||||
<SpecParams>
|
||||
<index>17</index>
|
||||
<model>pcie-root-port</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>c2ef6c73-f633-41c1-8736-7e9c8d748ac2</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>pci</Device>
|
||||
<rasd:Address>{type=pci, slot=0x04, bus=0x00, domain=0x0000, function=0x1}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>pci.18</Alias>
|
||||
<SpecParams>
|
||||
<index>18</index>
|
||||
<model>pcie-root-port</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>5944d260-08c3-4f12-aa22-1e9ac76ae6c0</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>pci</Device>
|
||||
<rasd:Address>{type=pci, slot=0x04, bus=0x00, domain=0x0000, function=0x2}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>pci.19</Alias>
|
||||
<SpecParams>
|
||||
<index>19</index>
|
||||
<model>pcie-root-port</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>8c7ad6aa-ac22-4d98-86b7-45f3a13c98da</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>pci</Device>
|
||||
<rasd:Address>{type=pci, slot=0x04, bus=0x00, domain=0x0000, function=0x3}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>pci.20</Alias>
|
||||
<SpecParams>
|
||||
<index>20</index>
|
||||
<model>pcie-root-port</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>dc1cfae5-682d-4bb5-a53e-d604852e62cd</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>pci</Device>
|
||||
<rasd:Address>{type=pci, slot=0x04, bus=0x00, domain=0x0000, function=0x4}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>pci.21</Alias>
|
||||
<SpecParams>
|
||||
<index>21</index>
|
||||
<model>pcie-root-port</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>6117753b-8ce6-4568-8e09-c8b686396334</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>sata</Device>
|
||||
<rasd:Address>{type=pci, slot=0x1f, bus=0x00, domain=0x0000, function=0x2}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>ide</Alias>
|
||||
<SpecParams>
|
||||
<index>0</index>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>17976687-41f8-4f7c-97f5-a76a282c40e4</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>virtio-serial</Device>
|
||||
<rasd:Address>{type=pci, slot=0x00, bus=0x03, domain=0x0000, function=0x0}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>ua-17976687-41f8-4f7c-97f5-a76a282c40e4</Alias>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>97f6991c-e4d5-11f0-9b4a-00163e6c35f4</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>ua-97f6991c-e4d5-11f0-9b4a-00163e6c35f4</Alias>
|
||||
<SpecParams>
|
||||
<source>urandom</source>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>0eb75625-9891-4b03-9541-c58c43c323b2</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>virtio-scsi</Device>
|
||||
<rasd:Address>{type=pci, slot=0x00, bus=0x02, domain=0x0000, function=0x0}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>ua-0eb75625-9891-4b03-9541-c58c43c323b2</Alias>
|
||||
<SpecParams>
|
||||
<ioThreadId></ioThreadId>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>59536909-bac6-4202-b2ad-d84a22a41013</rasd:InstanceId>
|
||||
<Type>balloon</Type>
|
||||
<Device>memballoon</Device>
|
||||
<rasd:Address>{type=pci, slot=0x00, bus=0x05, domain=0x0000, function=0x0}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>true</IsReadOnly>
|
||||
<Alias>ua-59536909-bac6-4202-b2ad-d84a22a41013</Alias>
|
||||
<SpecParams>
|
||||
<model>virtio</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
<Item>
|
||||
<rasd:ResourceType>0</rasd:ResourceType>
|
||||
<rasd:InstanceId>e95647b0-4bb2-4ccb-b867-cbde06311038</rasd:InstanceId>
|
||||
<Type>controller</Type>
|
||||
<Device>usb</Device>
|
||||
<rasd:Address>{type=pci, slot=0x00, bus=0x04, domain=0x0000, function=0x0}</rasd:Address>
|
||||
<BootOrder>0</BootOrder>
|
||||
<IsPlugged>true</IsPlugged>
|
||||
<IsReadOnly>false</IsReadOnly>
|
||||
<Alias>ua-e95647b0-4bb2-4ccb-b867-cbde06311038</Alias>
|
||||
<SpecParams>
|
||||
<index>0</index>
|
||||
<model>qemu-xhci</model>
|
||||
</SpecParams>
|
||||
</Item>
|
||||
</Section>
|
||||
<Section xsi:type="ovf:SnapshotsSection_Type">
|
||||
<Snapshot ovf:id="3d298647-57d5-4a2b-90e7-226bdb4f1800">
|
||||
<Type>ACTIVE</Type>
|
||||
<Description>Active VM</Description>
|
||||
<CreationDate>2026/01/07 13:37:09</CreationDate>
|
||||
</Snapshot>
|
||||
</Section>
|
||||
</Content>
|
||||
</ovf:Envelope>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package org.apache.cloudstack.veeam.api.dto;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class OvfXmlUtilTest {
|
||||
|
||||
String configuration = "<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\">" +
|
||||
"<Content ovf:id=\"out\" xsi:type=\"ovf:VirtualSystem_Type\"><Name>adm-v9</Name><Description>adm-v9</Description>"+
|
||||
"<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>MegaBytes</rasd:AllocationUnits><rasd:VirtualQuantity>512</rasd:VirtualQuantity></Item>" +
|
||||
"</Section></Content></ovf:Envelope>";
|
||||
|
||||
@Test
|
||||
public void updateFromXml_parsesDetails() {
|
||||
Vm vm = new Vm();
|
||||
OvfXmlUtil.updateFromXml(vm, configuration);
|
||||
|
||||
assertEquals(String.valueOf(512L), vm.getMemory());
|
||||
assertEquals("1", vm.getCpu().getTopology().getSockets());
|
||||
assertEquals("1", vm.getCpu().getTopology().getCores());
|
||||
assertEquals("1", vm.getCpu().getTopology().getThreads());
|
||||
}
|
||||
}
|
||||
|
|
@ -137,6 +137,10 @@ public class IncrementalBackupServiceImpl extends ManagerBase implements Increme
|
|||
throw new CloudRuntimeException("VM must be running or stopped to start backup");
|
||||
}
|
||||
|
||||
if (vm.getBackupOfferingId() == null) {
|
||||
throw new CloudRuntimeException("VM not assigned a backup offering");
|
||||
}
|
||||
|
||||
Backup existingBackup = backupDao.findByVmId(vmId);
|
||||
if (existingBackup != null && existingBackup.getStatus() == Backup.Status.BackingUp) {
|
||||
throw new CloudRuntimeException("Backup already in progress for VM: " + vmId);
|
||||
|
|
|
|||
Loading…
Reference in New Issue