changes for discovery

Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
This commit is contained in:
Abhishek Kumar 2026-01-22 12:20:31 +05:30
parent 065ec85589
commit a30eb280e5
15 changed files with 617 additions and 57 deletions

View File

@ -32,7 +32,6 @@ import org.apache.cloudstack.veeam.api.dto.DataCenter;
import org.apache.cloudstack.veeam.api.dto.DataCenters;
import org.apache.cloudstack.veeam.api.dto.StorageDomain;
import org.apache.cloudstack.veeam.api.dto.StorageDomains;
import org.apache.cloudstack.veeam.api.request.VmListQuery;
import org.apache.cloudstack.veeam.utils.Negotiation;
import org.apache.cloudstack.veeam.utils.PathUtil;
@ -106,18 +105,6 @@ public class DataCentersRouteHandler extends ManagerBase implements RouteHandler
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found");
}
/**
* Matches /api/datacenters/{id} where {id} is a single path segment (no extra '/').
* Returns id or null.
*/
private static String matchSinglePathParam(final String path, final String prefix) {
if (!path.startsWith(prefix)) return null;
final String rest = path.substring(prefix.length()); // after "/api/datacenters/"
if (rest.isEmpty()) return null;
if (rest.contains("/")) return null; // ensure only 1 segment
return rest;
}
public void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
final List<DataCenter> result = DataCenterVOToDataCenterConverter.toDCList(listDCs());
@ -126,23 +113,6 @@ public class DataCentersRouteHandler extends ManagerBase implements RouteHandler
io.getWriter().write(resp, 200, response, outFormat);
}
private static VmListQuery fromRequest(final HttpServletRequest req) {
final VmListQuery q = new VmListQuery();
q.setSearch(req.getParameter("search"));
q.setMax(parseIntOrNull(req.getParameter("max")));
q.setPage(parseIntOrNull(req.getParameter("page")));
return q;
}
private static Integer parseIntOrNull(final String s) {
if (s == null || s.trim().isEmpty()) return null;
try {
return Integer.parseInt(s.trim());
} catch (NumberFormatException e) {
return Integer.valueOf(-1); // will be rejected by validation above
}
}
protected List<DataCenterVO> listDCs() {
return dataCenterDao.listAll();
}

View File

@ -0,0 +1,111 @@
// 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.api.converter.VolumeJoinVOToDiskConverter;
import org.apache.cloudstack.veeam.api.dto.Disk;
import org.apache.cloudstack.veeam.api.dto.Disks;
import org.apache.cloudstack.veeam.utils.Negotiation;
import org.apache.cloudstack.veeam.utils.PathUtil;
import com.cloud.api.query.dao.VolumeJoinDao;
import com.cloud.api.query.vo.VolumeJoinVO;
import com.cloud.utils.Pair;
import com.cloud.utils.component.ManagerBase;
public class DisksRouteHandler extends ManagerBase implements RouteHandler {
public static final String BASE_ROUTE = "/api/disks";
@Inject
VolumeJoinDao volumeJoinDao;
@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;
}
Pair<String, String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
if (idAndSubPath != null) {
// /api/disks/{id}
if (idAndSubPath.first() != null) {
if (idAndSubPath.second() == null) {
handleGetById(idAndSubPath.first(), resp, outFormat, io);
return;
}
}
}
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found");
}
public void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
final List<Disk> result = VolumeJoinVOToDiskConverter.toDiskList(listDisks());
final Disks response = new Disks(result);
io.getWriter().write(resp, 200, response, outFormat);
}
protected List<VolumeJoinVO> listDisks() {
return volumeJoinDao.listAll();
}
public void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
final VeeamControlServlet io) throws IOException {
final VolumeJoinVO volumeJoinVO = volumeJoinDao.findByUuid(id);
if (volumeJoinVO == null) {
io.notFound(resp, "DataCenter not found: " + id, outFormat);
return;
}
Disk response = VolumeJoinVOToDiskConverter.toDisk(volumeJoinVO);
io.getWriter().write(resp, 200, response, outFormat);
}
}

View File

@ -28,6 +28,9 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.cloudstack.veeam.RouteHandler;
import org.apache.cloudstack.veeam.VeeamControlServlet;
import org.apache.cloudstack.veeam.api.converter.UserVmJoinVOToVmConverter;
import org.apache.cloudstack.veeam.api.converter.VolumeJoinVOToDiskConverter;
import org.apache.cloudstack.veeam.api.dto.DiskAttachment;
import org.apache.cloudstack.veeam.api.dto.DiskAttachments;
import org.apache.cloudstack.veeam.api.dto.Vm;
import org.apache.cloudstack.veeam.api.request.VmListQuery;
import org.apache.cloudstack.veeam.api.request.VmSearchExpr;
@ -36,9 +39,12 @@ import org.apache.cloudstack.veeam.api.request.VmSearchParser;
import org.apache.cloudstack.veeam.api.response.VmCollectionResponse;
import org.apache.cloudstack.veeam.api.response.VmEntityResponse;
import org.apache.cloudstack.veeam.utils.Negotiation;
import org.apache.cloudstack.veeam.utils.PathUtil;
import com.cloud.api.query.dao.UserVmJoinDao;
import com.cloud.api.query.dao.VolumeJoinDao;
import com.cloud.api.query.vo.UserVmJoinVO;
import com.cloud.utils.Pair;
import com.cloud.utils.component.ManagerBase;
public class VmsRouteHandler extends ManagerBase implements RouteHandler {
@ -50,6 +56,9 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler {
@Inject
UserVmJoinDao userVmJoinDao;
@Inject
VolumeJoinDao volumeJoinDao;
private VmSearchParser searchParser;
@Override
@ -83,33 +92,24 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler {
handleGet(req, resp, outFormat, io);
return;
}
// /api/vms/{id}
final String vmId = matchSinglePathParam(sanitizedPath, BASE_ROUTE + "/");
if (vmId != null) {
if (!"GET".equalsIgnoreCase(method)) {
io.methodNotAllowed(resp, "GET", outFormat);
return;
Pair<String, String> idAndSubPath = PathUtil.extractIdAndSubPath(sanitizedPath, BASE_ROUTE);
if (idAndSubPath != null) {
// /api/vms/{id}
if (idAndSubPath.first() != null) {
if (idAndSubPath.second() == null) {
handleGetById(idAndSubPath.first(), resp, outFormat, io);
return;
}
if ("diskattachments".equals(idAndSubPath.second())) {
handleGetDisAttachmentsByVmId(idAndSubPath.first(), resp, outFormat, io);
return;
}
}
handleGetById(vmId, resp, outFormat, io);
return;
}
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found");
}
/**
* Matches /api/vms/{id} where {id} is a single path segment (no extra '/').
* Returns id or null.
*/
private static String matchSinglePathParam(final String path, final String prefix) {
if (!path.startsWith(prefix)) return null;
final String rest = path.substring(prefix.length()); // after "/api/vms/"
if (rest.isEmpty()) return null;
if (rest.contains("/")) return null; // ensure only 1 segment
return rest;
}
public void handleGet(final HttpServletRequest req, final HttpServletResponse resp,
Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException {
final VmListQuery q = fromRequest(req);
@ -182,4 +182,18 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler {
io.getWriter().write(resp, 200, response, outFormat);
}
public void handleGetDisAttachmentsByVmId(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat,
final VeeamControlServlet io) throws IOException {
final UserVmJoinVO userVmJoinVO = userVmJoinDao.findByUuid(id);
if (userVmJoinVO == null) {
io.notFound(resp, "VM not found: " + id, outFormat);
return;
}
List<DiskAttachment> disks = VolumeJoinVOToDiskConverter.toDiskAttachmentList(
volumeJoinDao.listByInstanceId(userVmJoinVO.getId()));
DiskAttachments response = new DiskAttachments(disks);
io.getWriter().write(resp, 200, response, outFormat);
}
}

View File

@ -66,28 +66,28 @@ public final class UserVmJoinVOToVmConverter {
}
final Ref template = buildRef(
basePath + ApiService.BASE_ROUTE,
"template",
"templates",
src.getTemplateUuid()
);
dst.template = template;
dst.originalTemplate = template;
dst.host = buildRef(
basePath + ApiService.BASE_ROUTE,
"host",
"hosts",
src.getHostUuid());
dst.cluster = buildRef(
basePath + ApiService.BASE_ROUTE,
"cluster",
"clusters",
src.getHostUuid());
dst.memory = src.getRamSize() * 1024L * 1024L;
dst.cpu = new Cpu(src.getArch(), new Topology(src.getCpu(), 1, 1));
dst.cpu = new Cpu(src.getArch(), new Topology(src.getCpu(), src.getCpu(), 1));
dst.os = new Os();
dst.os.type = src.getGuestOsId() % 2 == 0
? "windows"
: "linux";
dst.bios = new Bios();
dst.bios.type = "legacy";
dst.bios.type = "q35_secure_boot";
dst.type = "server";
dst.origin = "ovirt";
dst.actions = null;dst.link = List.of(

View File

@ -0,0 +1,198 @@
// 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.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.cloudstack.veeam.VeeamControlService;
import org.apache.cloudstack.veeam.api.ApiService;
import org.apache.cloudstack.veeam.api.dto.Actions;
import org.apache.cloudstack.veeam.api.dto.Disk;
import org.apache.cloudstack.veeam.api.dto.DiskAttachment;
import org.apache.cloudstack.veeam.api.dto.Link;
import org.apache.cloudstack.veeam.api.dto.Ref;
import com.cloud.api.ApiDBUtils;
import com.cloud.api.query.vo.VolumeJoinVO;
import com.cloud.storage.Storage;
import com.cloud.storage.Volume;
import com.cloud.storage.VolumeStats;
public class VolumeJoinVOToDiskConverter {
public static Disk toDisk(final VolumeJoinVO vol) {
final Disk disk = new Disk();
final String apiBase = VeeamControlService.ContextPath.value() + ApiService.BASE_ROUTE;
final String diskId = vol.getUuid();
final String diskHref = apiBase + "/disks/" + diskId;
disk.id = diskId;
disk.href = diskHref;
// Names
disk.name = vol.getName();
disk.alias = vol.getName();
disk.description = "";
// Sizes (bytes)
final long size = vol.getSize();
final long actualSize = vol.getVolumeStoreSize();
disk.provisionedSize = String.valueOf(size);
disk.actualSize = String.valueOf(actualSize);
disk.totalSize = String.valueOf(size);
VolumeStats vs = null;
if (List.of(Storage.ImageFormat.VHD, Storage.ImageFormat.QCOW2, Storage.ImageFormat.RAW).contains(vol.getFormat())) {
if (vol.getPath() != null) {
vs = ApiDBUtils.getVolumeStatistics(vol.getPath());
}
} else if (vol.getFormat() == Storage.ImageFormat.OVA) {
if (vol.getChainInfo() != null) {
vs = ApiDBUtils.getVolumeStatistics(vol.getChainInfo());
}
}
if (vs != null) {
disk.totalSize = String.valueOf(vs.getVirtualSize());
disk.actualSize = String.valueOf(vs.getPhysicalSize());
}
// Disk format
disk.format = mapFormat(vol.getFormat());
disk.qcowVersion = "qcow2_v3";
// Content & storage
disk.contentType = "data";
disk.storageType = "image";
disk.sparse = "true";
disk.shareable = "false";
// Status
disk.status = mapStatus(vol.getState());
// Backup-related flags (safe defaults)
disk.backup = "none";
disk.propagateErrors = "false";
disk.wipeAfterDelete = "false";
// Image ID (best-effort)
disk.imageId = vol.getPath(); // acceptable placeholder
// Disk profile (optional)
disk.diskProfile = Ref.of(
apiBase + "/diskprofiles/" + vol.getDiskOfferingId(),
String.valueOf(vol.getDiskOfferingId())
);
// Storage domains
if (vol.getPoolUuid() != null) {
Disk.StorageDomains sds = new Disk.StorageDomains();
sds.storageDomain = List.of(
Ref.of(
apiBase + "/storagedomains/" + vol.getPoolUuid(),
vol.getPoolUuid()
)
);
disk.storageDomains = sds;
}
// Actions (Veeam checks presence, not behavior)
disk.actions = defaultDiskActions(diskHref);
// Links
disk.link = List.of(
new Link("disksnapshots", diskHref + "/disksnapshots")
);
return disk;
}
public static List<Disk> toDiskList(final List<VolumeJoinVO> srcList) {
return srcList.stream()
.map(VolumeJoinVOToDiskConverter::toDisk)
.collect(Collectors.toList());
}
public static DiskAttachment toDiskAttachment(final VolumeJoinVO vol) {
final DiskAttachment da = new DiskAttachment();
final String apiBase = VeeamControlService.ContextPath.value() + ApiService.BASE_ROUTE;
final String diskAttachmentId = vol.getUuid();
final String diskAttachmentHref = apiBase + "/diskattachments/" + diskAttachmentId;
da.id = diskAttachmentId;
da.href = diskAttachmentHref;
// Links
da.disk = Ref.of(
apiBase + "/disks/" + vol.getUuid(),
vol.getUuid()
);
da.vm = Ref.of(
apiBase + "/vms/" + vol.getVmUuid(),
vol.getVmUuid()
);
// Properties
da.active = "true";
da.bootable = "false";
da.iface = "virtio_scsi";
da.logicalName = vol.getName();
da.readOnly = "false";
da.passDiscard = "false";
return da;
}
public static List<DiskAttachment> toDiskAttachmentList(final List<VolumeJoinVO> srcList) {
return srcList.stream()
.map(VolumeJoinVOToDiskConverter::toDiskAttachment)
.collect(Collectors.toList());
}
private static String mapFormat(final Storage.ImageFormat format) {
if (format == null) {
return "cow";
}
switch (format) {
case RAW:
return "raw";
case QCOW2:
default:
return "cow";
}
}
private static String mapStatus(final Volume.State state) {
if (state == null) {
return "ok";
}
switch (state.name().toLowerCase()) {
case "ready":
case "allocated":
return "ok";
default:
return "locked";
}
}
private static Actions defaultDiskActions(final String diskHref) {
return new Actions(Collections.emptyList());
}
}

View File

@ -23,6 +23,8 @@ import com.fasterxml.jackson.annotation.JsonInclude;
public final class Bios {
public String type; // "uefi" or "bios" or whatever mapping you choose
public BootMenu bootMenu = new BootMenu();
public Bios() {}
public Bios(final String type) {

View File

@ -0,0 +1,26 @@
// 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 {
public String enabled = "false";
}

View File

@ -0,0 +1,96 @@
// 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;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import java.util.List;
@JsonInclude(JsonInclude.Include.NON_NULL)
@JacksonXmlRootElement(localName = "disk")
public final class Disk {
@JsonProperty("actual_size")
public String actualSize;
public String alias;
public String backup;
@JsonProperty("content_type")
public String contentType;
public String format;
@JsonProperty("image_id")
public String imageId;
@JsonProperty("propagate_errors")
public String propagateErrors;
@JsonProperty("provisioned_size")
public String provisionedSize;
@JsonProperty("qcow_version")
public String qcowVersion;
public String shareable;
public String sparse;
public String status;
@JsonProperty("storage_type")
public String storageType;
@JsonProperty("total_size")
public String totalSize;
@JsonProperty("wipe_after_delete")
public String wipeAfterDelete;
@JsonProperty("disk_profile")
public Ref diskProfile;
public Ref quota;
@JsonProperty("storage_domains")
public StorageDomains storageDomains;
public Actions actions;
public String name;
public String description;
@JacksonXmlElementWrapper(useWrapping = false)
public List<Link> link;
public String href;
public String id;
public Disk() {}
@JsonInclude(JsonInclude.Include.NON_NULL)
@JacksonXmlRootElement(localName = "storage_domains")
public static final class StorageDomains {
@JsonProperty("storage_domain")
@JacksonXmlElementWrapper(useWrapping = false)
public List<Ref> storageDomain;
public StorageDomains() {}
}
}

View File

@ -0,0 +1,53 @@
// 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;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@JsonInclude(JsonInclude.Include.NON_NULL)
@JacksonXmlRootElement(localName = "disk_attachment")
public final class DiskAttachment {
public String active;
public String bootable;
@JsonProperty("interface")
public String iface; // virtio_scsi etc
@JsonProperty("logical_name")
public String logicalName;
@JsonProperty("pass_discard")
public String passDiscard;
@JsonProperty("read_only")
public String readOnly;
@JsonProperty("uses_scsi_reservation")
public String usesScsiReservation;
public Ref disk;
public Ref vm;
public String href;
public String id;
public DiskAttachment() {}
}

View File

@ -0,0 +1,40 @@
// 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;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import java.util.List;
@JsonInclude(JsonInclude.Include.NON_NULL)
@JacksonXmlRootElement(localName = "disk_attachments")
public final class DiskAttachments {
@JsonProperty("disk_attachment")
@JacksonXmlElementWrapper(useWrapping = false)
public List<DiskAttachment> diskAttachment;
public DiskAttachments() {}
public DiskAttachments(final List<DiskAttachment> diskAttachment) {
this.diskAttachment = diskAttachment;
}
}

View File

@ -0,0 +1,40 @@
// 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 = "disks")
public final class Disks {
@JsonProperty("disk")
@JacksonXmlElementWrapper(useWrapping = false)
public List<Disk> disk;
public Disks() {}
public Disks(final List<Disk> disk) {
this.disk = disk;
}
}

View File

@ -61,7 +61,7 @@ public final class Vm {
public Os os;
public Bios bios;
public boolean stateless; // true|false
public String stateless = "false"; // true|false
public String type; // "server"
public String origin; // "ovirt"

View File

@ -34,6 +34,7 @@
<bean id="veeamControlApiService" class="org.apache.cloudstack.veeam.api.ApiService" />
<bean id="vmsRouteHandler" class="org.apache.cloudstack.veeam.api.VmsRouteHandler"/>
<bean id="dataCentersRouteHandler" class="org.apache.cloudstack.veeam.api.DataCentersRouteHandler"/>
<bean id="disksRouteHandler" class="org.apache.cloudstack.veeam.api.DisksRouteHandler"/>
<bean id="veeamControlSsoService" class="org.apache.cloudstack.veeam.sso.SsoService"/>
<bean id="veeamControlService" class="org.apache.cloudstack.veeam.VeeamControlServiceImpl" >

View File

@ -34,4 +34,6 @@ public interface VolumeJoinDao extends GenericDao<VolumeJoinVO, Long> {
List<VolumeJoinVO> newVolumeView(Volume vol);
List<VolumeJoinVO> searchByIds(Long... ids);
List<VolumeJoinVO> listByInstanceId(long instanceId);
}

View File

@ -372,4 +372,11 @@ public class VolumeJoinDaoImpl extends GenericDaoBaseWithTagInformation<VolumeJo
return uvList;
}
@Override
public List<VolumeJoinVO> listByInstanceId(long instanceId) {
SearchCriteria<VolumeJoinVO> sc = createSearchCriteria();
sc.addAnd("vmId", SearchCriteria.Op.EQ, instanceId);
return search(sc, null);
}
}