diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/DataCentersRouteHandler.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/DataCentersRouteHandler.java index d297fe9b516..c49f078121a 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/DataCentersRouteHandler.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/DataCentersRouteHandler.java @@ -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 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 listDCs() { return dataCenterDao.listAll(); } diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/DisksRouteHandler.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/DisksRouteHandler.java new file mode 100644 index 00000000000..ad7aed6455b --- /dev/null +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/DisksRouteHandler.java @@ -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 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 result = VolumeJoinVOToDiskConverter.toDiskList(listDisks()); + final Disks response = new Disks(result); + + io.getWriter().write(resp, 200, response, outFormat); + } + + protected List 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); + } +} diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/VmsRouteHandler.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/VmsRouteHandler.java index 23f626e326e..62e7c67dfa7 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/VmsRouteHandler.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/VmsRouteHandler.java @@ -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 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 disks = VolumeJoinVOToDiskConverter.toDiskAttachmentList( + volumeJoinDao.listByInstanceId(userVmJoinVO.getId())); + DiskAttachments response = new DiskAttachments(disks); + + io.getWriter().write(resp, 200, response, outFormat); + } } \ No newline at end of file diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/UserVmJoinVOToVmConverter.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/UserVmJoinVOToVmConverter.java index 760ab5c758c..4a8030149a8 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/UserVmJoinVOToVmConverter.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/UserVmJoinVOToVmConverter.java @@ -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( diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/VolumeJoinVOToDiskConverter.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/VolumeJoinVOToDiskConverter.java new file mode 100644 index 00000000000..55a25706a91 --- /dev/null +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/VolumeJoinVOToDiskConverter.java @@ -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 toDiskList(final List 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 toDiskAttachmentList(final List 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()); + } +} diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Bios.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Bios.java index f1de8cf3a5a..fa9e46ba87c 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Bios.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Bios.java @@ -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) { diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/BootMenu.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/BootMenu.java new file mode 100644 index 00000000000..714b256596a --- /dev/null +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/BootMenu.java @@ -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"; +} diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Disk.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Disk.java new file mode 100644 index 00000000000..812501f5615 --- /dev/null +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Disk.java @@ -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; + + 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 storageDomain; + public StorageDomains() {} + } +} diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/DiskAttachment.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/DiskAttachment.java new file mode 100644 index 00000000000..ca041e993f5 --- /dev/null +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/DiskAttachment.java @@ -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() {} +} diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/DiskAttachments.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/DiskAttachments.java new file mode 100644 index 00000000000..deebb9d310a --- /dev/null +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/DiskAttachments.java @@ -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; + + public DiskAttachments() {} + + public DiskAttachments(final List diskAttachment) { + this.diskAttachment = diskAttachment; + } +} diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Disks.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Disks.java new file mode 100644 index 00000000000..302ff3adfd8 --- /dev/null +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Disks.java @@ -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; + + public Disks() {} + + public Disks(final List disk) { + this.disk = disk; + } +} \ No newline at end of file diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Vm.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Vm.java index 4bba580a971..5a21f84c4ae 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Vm.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Vm.java @@ -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" diff --git a/plugins/integrations/veeam-control-service/src/main/resources/META-INF/cloudstack/veeam-control-service/spring-veeam-control-service-context.xml b/plugins/integrations/veeam-control-service/src/main/resources/META-INF/cloudstack/veeam-control-service/spring-veeam-control-service-context.xml index 6e75d838438..0c553d8e553 100644 --- a/plugins/integrations/veeam-control-service/src/main/resources/META-INF/cloudstack/veeam-control-service/spring-veeam-control-service-context.xml +++ b/plugins/integrations/veeam-control-service/src/main/resources/META-INF/cloudstack/veeam-control-service/spring-veeam-control-service-context.xml @@ -34,6 +34,7 @@ + diff --git a/server/src/main/java/com/cloud/api/query/dao/VolumeJoinDao.java b/server/src/main/java/com/cloud/api/query/dao/VolumeJoinDao.java index ebcf0bca391..87485e86fc9 100644 --- a/server/src/main/java/com/cloud/api/query/dao/VolumeJoinDao.java +++ b/server/src/main/java/com/cloud/api/query/dao/VolumeJoinDao.java @@ -34,4 +34,6 @@ public interface VolumeJoinDao extends GenericDao { List newVolumeView(Volume vol); List searchByIds(Long... ids); + + List listByInstanceId(long instanceId); } diff --git a/server/src/main/java/com/cloud/api/query/dao/VolumeJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/VolumeJoinDaoImpl.java index 4f5d984c969..9361abef604 100644 --- a/server/src/main/java/com/cloud/api/query/dao/VolumeJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/VolumeJoinDaoImpl.java @@ -372,4 +372,11 @@ public class VolumeJoinDaoImpl extends GenericDaoBaseWithTagInformation listByInstanceId(long instanceId) { + SearchCriteria sc = createSearchCriteria(); + sc.addAnd("vmId", SearchCriteria.Op.EQ, instanceId); + return search(sc, null); + } + }