diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/RouteHandler.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/RouteHandler.java index fa7ab174f2b..a955eeac020 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/RouteHandler.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/RouteHandler.java @@ -19,6 +19,7 @@ package org.apache.cloudstack.veeam; import java.io.BufferedReader; import java.io.IOException; +import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -64,4 +65,10 @@ public interface RouteHandler extends Adapter { return null; } } + + static Map getRequestParams(HttpServletRequest req) { + return req.getParameterMap().entrySet().stream() + .filter(e -> e.getValue() != null && e.getValue().length > 0) + .collect(java.util.stream.Collectors.toMap(Map.Entry::getKey, e -> e.getValue()[0])); + } } diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/VeeamControlServlet.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/VeeamControlServlet.java index 69f6b9fb5c0..8016bf9c17a 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/VeeamControlServlet.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/VeeamControlServlet.java @@ -27,8 +27,8 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.cloudstack.veeam.utils.Negotiation; import org.apache.cloudstack.veeam.utils.Mapper; +import org.apache.cloudstack.veeam.utils.Negotiation; import org.apache.cloudstack.veeam.utils.ResponseWriter; import org.apache.commons.collections4.CollectionUtils; import org.apache.logging.log4j.LogManager; @@ -36,6 +36,7 @@ import org.apache.logging.log4j.Logger; public class VeeamControlServlet extends HttpServlet { private static final Logger LOGGER = LogManager.getLogger(VeeamControlServlet.class); + private static final boolean LOG_REQUESTS = false; private final ResponseWriter writer; private final Mapper mapper; @@ -63,6 +64,32 @@ public class VeeamControlServlet extends HttpServlet { LOGGER.info("Received {} request for {} with out format: {}", method, path, outFormat); + logRequest(req, method, path); + + try { + if ("/".equals(path)) { + handleRoot(req, resp, outFormat); + return; + } + + if (CollectionUtils.isNotEmpty(this.routeHandlers)) { + for (RouteHandler handler : this.routeHandlers) { + if (handler.canHandle(method, path)) { + handler.handle(req, resp, path, outFormat, this); + return; + } + } + } + notFound(resp, null, outFormat); + } catch (Error e) { + writer.writeFault(resp, e.status, e.message, null, outFormat); + } + } + + private static void logRequest(HttpServletRequest req, String method, String path) { + if (!LOG_REQUESTS) { + return; + } // Add a log to give all info about the request try { StringBuilder details = new StringBuilder(); @@ -91,25 +118,6 @@ public class VeeamControlServlet extends HttpServlet { } catch (Exception e) { LOGGER.debug("Failed to capture request details", e); } - - try { - if ("/".equals(path)) { - handleRoot(req, resp, outFormat); - return; - } - - if (CollectionUtils.isNotEmpty(this.routeHandlers)) { - for (RouteHandler handler : this.routeHandlers) { - if (handler.canHandle(method, path)) { - handler.handle(req, resp, path, outFormat, this); - return; - } - } - } - resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found"); - } catch (Error e) { - writer.writeFault(resp, e.status, e.message, null, outFormat); - } } private String normalize(String pathInfo) { @@ -133,16 +141,16 @@ public class VeeamControlServlet extends HttpServlet { public void methodNotAllowed(final HttpServletResponse resp, final String allow, final Negotiation.OutFormat outFormat) throws IOException { resp.setHeader("Allow", allow); - writer.writeFault(resp, 405, "Method Not Allowed", "Allowed methods: " + allow, outFormat); + writer.writeFault(resp, HttpServletResponse.SC_METHOD_NOT_ALLOWED, "Method Not Allowed", "Allowed methods: " + allow, outFormat); } public void badRequest(final HttpServletResponse resp, String detail, Negotiation.OutFormat outFormat) throws IOException { - writer.writeFault(resp, 400, "Bad request", detail, outFormat); + writer.writeFault(resp, HttpServletResponse.SC_BAD_REQUEST, "Bad request", detail, outFormat); } public void notFound(final HttpServletResponse resp, String detail, Negotiation.OutFormat outFormat) throws IOException { - writer.writeFault(resp, 404, "Not found", detail, outFormat); + writer.writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", detail, outFormat); } public static class Error extends RuntimeException { diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/adapter/ServerAdapter.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/adapter/ServerAdapter.java index b7d8e269976..468d329b07b 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/adapter/ServerAdapter.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/adapter/ServerAdapter.java @@ -17,6 +17,7 @@ package org.apache.cloudstack.veeam.adapter; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Base64; import java.util.Collections; @@ -24,7 +25,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; import javax.inject.Inject; @@ -46,6 +46,8 @@ import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd; import org.apache.cloudstack.api.command.user.vm.ListVMsCmd; import org.apache.cloudstack.api.command.user.vm.StartVMCmd; import org.apache.cloudstack.api.command.user.vm.StopVMCmd; +import org.apache.cloudstack.api.command.user.vmsnapshot.CreateVMSnapshotCmd; +import org.apache.cloudstack.api.command.user.vmsnapshot.DeleteVMSnapshotCmd; import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; import org.apache.cloudstack.api.command.user.volume.DeleteVolumeCmd; @@ -73,6 +75,7 @@ import org.apache.cloudstack.veeam.api.converter.NetworkVOToVnicProfileConverter import org.apache.cloudstack.veeam.api.converter.NicVOToNicConverter; import org.apache.cloudstack.veeam.api.converter.StoreVOToStorageDomainConverter; import org.apache.cloudstack.veeam.api.converter.UserVmJoinVOToVmConverter; +import org.apache.cloudstack.veeam.api.converter.VmSnapshotVOToSnapshotConverter; import org.apache.cloudstack.veeam.api.converter.VolumeJoinVOToDiskConverter; import org.apache.cloudstack.veeam.api.dto.Cluster; import org.apache.cloudstack.veeam.api.dto.DataCenter; @@ -84,6 +87,7 @@ 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.Ref; +import org.apache.cloudstack.veeam.api.dto.Snapshot; import org.apache.cloudstack.veeam.api.dto.StorageDomain; import org.apache.cloudstack.veeam.api.dto.Vm; import org.apache.cloudstack.veeam.api.dto.VmAction; @@ -139,8 +143,12 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.NicVO; import com.cloud.vm.UserVmService; import com.cloud.vm.UserVmVO; +import com.cloud.vm.VmDetailConstants; import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.snapshot.VMSnapshotService; +import com.cloud.vm.snapshot.VMSnapshotVO; +import com.cloud.vm.snapshot.dao.VMSnapshotDao; public class ServerAdapter extends ManagerBase { private static final String SERVICE_ACCOUNT_NAME = "veemserviceuser"; @@ -162,6 +170,7 @@ public class ServerAdapter extends ManagerBase { ResizeVolumeCmd.class, ListNetworksCmd.class ); + public static final String GUEST_CPU_MODE = "host-passthrough"; @Inject RoleService roleService; @@ -238,7 +247,13 @@ public class ServerAdapter extends ManagerBase { @Inject AsyncJobJoinDao asyncJobJoinDao; - private Map jobsMap = new ConcurrentHashMap<>(); + @Inject + VMSnapshotDao vmSnapshotDao; + + @Inject + VMSnapshotService vmSnapshotService; + + //ToDo: check access on objects protected Role createServiceAccountRole() { Role role = roleService.createRole(SERVICE_ACCOUNT_ROLE_NAME, RoleType.User, @@ -383,13 +398,13 @@ public class ServerAdapter extends ManagerBase { return NetworkVOToVnicProfileConverter.toVnicProfile(vo, this::getZoneById); } - public List listAllUserVms() { + public List listAllInstances() { // Todo: add filtering, pagination List vms = userVmJoinDao.listAll(); return UserVmJoinVOToVmConverter.toVmList(vms, this::getHostById); } - public Vm getVm(String uuid) { + public Vm getInstance(String uuid) { UserVmJoinVO vo = userVmJoinDao.findByUuid(uuid); if (vo == null) { throw new InvalidParameterValueException("VM with ID " + uuid + " not found"); @@ -398,7 +413,7 @@ public class ServerAdapter extends ManagerBase { this::listNicsByInstance); } - public Vm handleCreateVm(Vm request) { + public Vm createInstance(Vm request) { if (request == null) { throw new InvalidParameterValueException("Request disk data is empty"); } @@ -424,14 +439,14 @@ public class ServerAdapter extends ManagerBase { } Long memory = null; try { - memory = request.memory; + memory = Long.valueOf(request.memory); } catch (Exception ignored) {} if (memory == null) { throw new InvalidParameterValueException("Memory must be specified"); } String userdata = null; if (request.getInitialization() != null) { - userdata = request.getInitialization().getContentData(); + userdata = request.getInitialization().getCustomScript(); } ApiConstants.BootType bootType = ApiConstants.BootType.BIOS; ApiConstants.BootMode bootMode = ApiConstants.BootMode.LEGACY; @@ -442,7 +457,7 @@ public class ServerAdapter extends ManagerBase { Pair serviceUserAccount = createServiceAccountIfNeeded(); CallContext ctx = CallContext.register(serviceUserAccount.first(), serviceUserAccount.second()); try { - return createVm(zoneId, clusterId, name, cpu, memory, userdata, bootType, bootMode); + return createInstance(zoneId, clusterId, name, cpu, memory, userdata, bootType, bootMode); } finally { CallContext.unregister(); } @@ -463,20 +478,21 @@ public class ServerAdapter extends ManagerBase { return serviceOfferingDao.findByUuid(uuid); } - protected Vm createVm(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, 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"); } DeployVMCmdByAdmin cmd = new DeployVMCmdByAdmin(); + cmd.setHttpMethod(BaseCmd.HTTPMethod.POST.name()); ComponentContext.inject(cmd); cmd.setZoneId(zoneId); cmd.setClusterId(clusterId); cmd.setName(name); cmd.setServiceOfferingId(serviceOffering.getId()); if (StringUtils.isNotEmpty(userdata)) { - cmd.setUserData(Base64.getEncoder().encodeToString(userdata.getBytes())); + cmd.setUserData(Base64.getEncoder().encodeToString(userdata.getBytes(StandardCharsets.UTF_8))); } if (bootType != null) { cmd.setBootType(bootType.toString()); @@ -487,6 +503,11 @@ public class ServerAdapter extends ManagerBase { // ToDo: handle other. cmd.setHypervisor(Hypervisor.HypervisorType.KVM.name()); cmd.setBlankInstance(true); + Map details = new HashMap<>(); + details.put(VmDetailConstants.GUEST_CPU_MODE, GUEST_CPU_MODE); + Map> map = new HashMap<>(); + map.put(0, details); + cmd.setDetails(map); try { UserVm vm = userVmService.createVirtualMachine(cmd); vm = userVmService.finalizeCreateVirtualMachine(vm.getId()); @@ -498,7 +519,11 @@ public class ServerAdapter extends ManagerBase { } } - public void deleteVm(String uuid) { + public Vm updateInstance(String uuid, Vm request) { + return getInstance(uuid); + } + + public void deleteInstance(String uuid) { UserVmVO vo = userVmDao.findByUuid(uuid); if (vo == null) { throw new InvalidParameterValueException("VM with ID " + uuid + " not found"); @@ -510,7 +535,7 @@ public class ServerAdapter extends ManagerBase { } } - public VmAction startVm(String uuid) { + public VmAction startInstance(String uuid) { UserVmVO vo = userVmDao.findByUuid(uuid); if (vo == null) { throw new InvalidParameterValueException("VM with ID " + uuid + " not found"); @@ -519,6 +544,7 @@ public class ServerAdapter extends ManagerBase { CallContext ctx = CallContext.register(serviceUserAccount.first(), serviceUserAccount.second()); try { StartVMCmd cmd = new StartVMCmd(); + cmd.setHttpMethod(BaseCmd.HTTPMethod.POST.name()); ComponentContext.inject(cmd); Map params = new HashMap<>(); params.put(ApiConstants.ID, vo.getUuid()); @@ -534,7 +560,7 @@ public class ServerAdapter extends ManagerBase { } } - public VmAction stopVm(String uuid) { + public VmAction stopInstance(String uuid) { UserVmVO vo = userVmDao.findByUuid(uuid); if (vo == null) { throw new InvalidParameterValueException("VM with ID " + uuid + " not found"); @@ -543,6 +569,7 @@ public class ServerAdapter extends ManagerBase { CallContext ctx = CallContext.register(serviceUserAccount.first(), serviceUserAccount.second()); try { StopVMCmd cmd = new StopVMCmd(); + cmd.setHttpMethod(BaseCmd.HTTPMethod.POST.name()); ComponentContext.inject(cmd); Map params = new HashMap<>(); params.put(ApiConstants.ID, vo.getUuid()); @@ -559,7 +586,7 @@ public class ServerAdapter extends ManagerBase { } } - public VmAction shutdownVm(String uuid) { + public VmAction shutdownInstance(String uuid) { UserVmVO vo = userVmDao.findByUuid(uuid); if (vo == null) { throw new InvalidParameterValueException("VM with ID " + uuid + " not found"); @@ -568,6 +595,7 @@ public class ServerAdapter extends ManagerBase { CallContext ctx = CallContext.register(serviceUserAccount.first(), serviceUserAccount.second()); try { StopVMCmd cmd = new StopVMCmd(); + cmd.setHttpMethod(BaseCmd.HTTPMethod.POST.name()); ComponentContext.inject(cmd); Map params = new HashMap<>(); params.put(ApiConstants.ID, vo.getUuid()); @@ -610,7 +638,7 @@ public class ServerAdapter extends ManagerBase { return listDiskAttachmentsByInstanceId(vo.getId()); } - public DiskAttachment handleVmAttachDisk(final String vmUuid, final DiskAttachment request) { + public DiskAttachment handleInstanceAttachDisk(final String vmUuid, final DiskAttachment request) { UserVmVO vmVo = userVmDao.findByUuid(vmUuid); if (vmVo == null) { throw new InvalidParameterValueException("VM with ID " + vmUuid + " not found"); @@ -729,7 +757,7 @@ public class ServerAdapter extends ManagerBase { return listNicsByInstance(vo.getId(), vo.getUuid()); } - public List listNicsByInstanceId(final String uuid) { + public List listNicsByInstanceUuid(final String uuid) { UserVmVO vo = userVmDao.findByUuid(uuid); if (vo == null) { throw new InvalidParameterValueException("VM with ID " + uuid + " not found"); @@ -737,7 +765,7 @@ public class ServerAdapter extends ManagerBase { return listNicsByInstance(vo.getId(), vo.getUuid()); } - public Nic handleVmAttachNic(final String vmUuid, final Nic request) { + public Nic handleAttachInstanceNic(final String vmUuid, final Nic request) { UserVmVO vmVo = userVmDao.findByUuid(vmUuid); if (vmVo == null) { throw new InvalidParameterValueException("VM with ID " + vmUuid + " not found"); @@ -860,28 +888,98 @@ public class ServerAdapter extends ManagerBase { } public List listAllJobs() { + // ToDo: find active jobs for service account return Collections.emptyList(); } - public Job getTempJob(String uuid) { -// final ClusterVO vo = clusterDao.findByUuid(uuid); -// if (vo == null) { -// throw new InvalidParameterValueException("Cluster with ID " + uuid + " not found"); -// } - long startTime = jobsMap.computeIfAbsent(uuid, k -> System.currentTimeMillis()); - long elapsed = System.currentTimeMillis() - startTime; - if (elapsed > 10000L) { - return AsyncJobJoinVOToJobConverter.toJob(uuid, "finished", startTime); - } else { - return AsyncJobJoinVOToJobConverter.toJob(uuid, "started", startTime); - } - } - public Job getJob(String uuid) { - final AsyncJobJoinVO vo = asyncJobJoinDao.findByUuid(uuid); + final AsyncJobJoinVO vo = asyncJobJoinDao.findByUuidIncludingRemoved(uuid); if (vo == null) { throw new InvalidParameterValueException("Job with ID " + uuid + " not found"); } return AsyncJobJoinVOToJobConverter.toJob(vo); } + + public List listSnapshotsByInstanceUuid(final String uuid) { + UserVmVO vo = userVmDao.findByUuid(uuid); + if (vo == null) { + throw new InvalidParameterValueException("VM with ID " + uuid + " not found"); + } + List snapshots = vmSnapshotDao.findByVm(vo.getId()); + return VmSnapshotVOToSnapshotConverter.toSnapshotList(snapshots, vo.getUuid()); + } + + public Snapshot handleCreateInstanceSnapshot(final String vmUuid, final Snapshot request) { + UserVmVO vmVo = userVmDao.findByUuid(vmUuid); + if (vmVo == null) { + throw new InvalidParameterValueException("VM with ID " + vmUuid + " not found"); + } + Pair serviceUserAccount = createServiceAccountIfNeeded(); + CallContext ctx = CallContext.register(serviceUserAccount.first(), serviceUserAccount.second()); + try { + CreateVMSnapshotCmd cmd = new CreateVMSnapshotCmd(); + ComponentContext.inject(cmd); + Map params = new HashMap<>(); + params.put(ApiConstants.VIRTUAL_MACHINE_ID, vmVo.getUuid()); + params.put(ApiConstants.VM_SNAPSHOT_DESCRIPTION, request.getDescription()); + params.put(ApiConstants.VM_SNAPSHOT_MEMORY, String.valueOf(Boolean.parseBoolean(request.getPersistMemorystate()))); + ApiServerService.AsyncCmdResult result = + apiServerService.processAsyncCmd(cmd, params, ctx, serviceUserAccount.first().getId(), + serviceUserAccount.second()); + if (result.objectId == null) { + throw new CloudRuntimeException("No snapshot ID returned"); + } + VMSnapshotVO vo = vmSnapshotDao.findById(result.objectId); + if (vo == null) { + throw new CloudRuntimeException("Snapshot not found"); + } + return VmSnapshotVOToSnapshotConverter.toSnapshot(vo, vmVo.getUuid()); + } catch (Exception e) { + throw new CloudRuntimeException("Failed to create snapshot: " + e.getMessage(), e); + } finally { + CallContext.unregister(); + } + } + + public Snapshot getSnapshot(String uuid) { + VMSnapshotVO vo = vmSnapshotDao.findByUuid(uuid); + if (vo == null) { + throw new InvalidParameterValueException("Snapshot with ID " + uuid + " not found"); + } + UserVmVO vm = userVmDao.findById(vo.getVmId()); + return VmSnapshotVOToSnapshotConverter.toSnapshot(vo, vm.getUuid()); + } + + public Snapshot deleteSnapshot(String uuid, boolean async) { + Snapshot snapshot = null; + VMSnapshotVO vo = vmSnapshotDao.findByUuid(uuid); + if (vo == null) { + throw new InvalidParameterValueException("Snapshot with ID " + uuid + " not found"); + } + Pair serviceUserAccount = createServiceAccountIfNeeded(); + CallContext ctx = CallContext.register(serviceUserAccount.first(), serviceUserAccount.second()); + try { + if (async) { + DeleteVMSnapshotCmd cmd = new DeleteVMSnapshotCmd(); + ComponentContext.inject(cmd); + Map params = new HashMap<>(); + params.put(ApiConstants.ID, vo.getUuid()); + apiServerService.processAsyncCmd(cmd, params, ctx, serviceUserAccount.first().getId(), + serviceUserAccount.second()); + vo = vmSnapshotDao.findById(vo.getId()); + if (vo == null) { + throw new CloudRuntimeException("Snapshot not found"); + } + UserVmVO vm = userVmDao.findById(vo.getVmId()); + snapshot = VmSnapshotVOToSnapshotConverter.toSnapshot(vo, vm.getUuid()); + } else { + vmSnapshotService.deleteVMSnapshot(vo.getId()); + } + } catch (Exception e) { + throw new CloudRuntimeException("Failed to delete snapshot: " + e.getMessage(), e); + } finally { + CallContext.unregister(); + } + return snapshot; + } } diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/ApiService.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/ApiService.java index 380a64715fe..dd0e4b25082 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/ApiService.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/ApiService.java @@ -61,7 +61,7 @@ public class ApiService extends ManagerBase implements RouteHandler { handleRootApiRequest(req, resp, outFormat, io); return; } - io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", null, outFormat); + io.notFound(resp, null, outFormat); } private void handleRootApiRequest(HttpServletRequest req, HttpServletResponse resp, Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException { diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/ClustersRouteHandler.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/ClustersRouteHandler.java index a80d0ec8d61..37ef228db9f 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/ClustersRouteHandler.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/ClustersRouteHandler.java @@ -79,7 +79,7 @@ public class ClustersRouteHandler extends ManagerBase implements RouteHandler { } } - resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found"); + io.notFound(resp, null, outFormat); } protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp, @@ -96,7 +96,7 @@ public class ClustersRouteHandler extends ManagerBase implements RouteHandler { Cluster response = serverAdapter.getCluster(id); io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat); } catch (InvalidParameterValueException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat); + io.notFound(resp, e.getMessage(), outFormat); } } } 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 e2e60fe8479..dd324eb9ee3 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 @@ -93,7 +93,7 @@ public class DataCentersRouteHandler extends ManagerBase implements RouteHandler } } - resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found"); + io.notFound(resp, null, outFormat); } protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp, @@ -110,7 +110,7 @@ public class DataCentersRouteHandler extends ManagerBase implements RouteHandler DataCenter response = serverAdapter.getDataCenter(id); io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat); } catch (InvalidParameterValueException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat); + io.notFound(resp, e.getMessage(), outFormat); } } @@ -121,7 +121,7 @@ public class DataCentersRouteHandler extends ManagerBase implements RouteHandler StorageDomains response = new StorageDomains(storageDomains); io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat); } catch (InvalidParameterValueException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat); + io.notFound(resp, e.getMessage(), outFormat); } } @@ -132,7 +132,7 @@ public class DataCentersRouteHandler extends ManagerBase implements RouteHandler Networks response = new Networks(networks); io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat); } catch (InvalidParameterValueException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat); + io.notFound(resp, e.getMessage(), outFormat); } } } 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 index 0bd618a8111..fa1248539b1 100644 --- 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 @@ -93,7 +93,7 @@ public class DisksRouteHandler extends ManagerBase implements RouteHandler { } } - resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found"); + io.notFound(resp, null, outFormat); } protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp, @@ -113,7 +113,7 @@ public class DisksRouteHandler extends ManagerBase implements RouteHandler { Disk response = serverAdapter.handleCreateDisk(request); io.getWriter().write(resp, HttpServletResponse.SC_CREATED, response, outFormat); } catch (JsonProcessingException | CloudRuntimeException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_BAD_REQUEST, "Bad request", e.getMessage(), outFormat); + io.badRequest(resp, e.getMessage(), outFormat); } } @@ -123,7 +123,7 @@ public class DisksRouteHandler extends ManagerBase implements RouteHandler { Disk response = serverAdapter.getDisk(id); io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat); } catch (InvalidParameterValueException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat); + io.notFound(resp, e.getMessage(), outFormat); } } @@ -133,7 +133,7 @@ public class DisksRouteHandler extends ManagerBase implements RouteHandler { serverAdapter.deleteDisk(id); io.getWriter().write(resp, HttpServletResponse.SC_OK, "Deleted disk ID: " + id, outFormat); } catch (InvalidParameterValueException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_BAD_REQUEST, "Bad request", e.getMessage(), outFormat); + io.badRequest(resp, e.getMessage(), outFormat); } } } diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/HostsRouteHandler.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/HostsRouteHandler.java index 37ac17b2364..efe41bfbe30 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/HostsRouteHandler.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/HostsRouteHandler.java @@ -79,7 +79,7 @@ public class HostsRouteHandler extends ManagerBase implements RouteHandler { } } - resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found"); + io.notFound(resp, null, outFormat); } protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp, @@ -96,7 +96,7 @@ public class HostsRouteHandler extends ManagerBase implements RouteHandler { Host response = serverAdapter.getHost(id); io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat); } catch (InvalidParameterValueException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat); + io.notFound(resp, e.getMessage(), outFormat); } } } diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/ImageTransfersRouteHandler.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/ImageTransfersRouteHandler.java index 3cdd5d0469d..9c77a28e426 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/ImageTransfersRouteHandler.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/ImageTransfersRouteHandler.java @@ -100,7 +100,7 @@ public class ImageTransfersRouteHandler extends ManagerBase implements RouteHand } } - resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found"); + io.notFound(resp, null, outFormat); } protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp, @@ -120,7 +120,7 @@ public class ImageTransfersRouteHandler extends ManagerBase implements RouteHand ImageTransfer response = serverAdapter.handleCreateImageTransfer(request); io.getWriter().write(resp, HttpServletResponse.SC_CREATED, response, outFormat); } catch (JsonProcessingException | CloudRuntimeException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_BAD_REQUEST, "Bad Request", e.getMessage(), outFormat); + io.badRequest(resp, e.getMessage(), outFormat); } } @@ -130,7 +130,7 @@ public class ImageTransfersRouteHandler extends ManagerBase implements RouteHand ImageTransfer response = serverAdapter.getImageTransfer(id); io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat); } catch (InvalidParameterValueException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat); + io.notFound(resp, e.getMessage(), outFormat); } } @@ -140,7 +140,7 @@ public class ImageTransfersRouteHandler extends ManagerBase implements RouteHand serverAdapter.handleCancelImageTransfer(id); io.getWriter().write(resp, HttpServletResponse.SC_OK, "Image transfer cancelled successfully", outFormat); } catch (InvalidParameterValueException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat); + io.notFound(resp, e.getMessage(), outFormat); } } @@ -150,7 +150,7 @@ public class ImageTransfersRouteHandler extends ManagerBase implements RouteHand serverAdapter.handleFinalizeImageTransfer(id); io.getWriter().write(resp, HttpServletResponse.SC_OK, "Image transfer finalized successfully", outFormat); } catch (CloudRuntimeException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat); + io.notFound(resp, e.getMessage(), outFormat); } } } diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/JobsRouteHandler.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/JobsRouteHandler.java index 5b5a62c6850..7213cdac5be 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/JobsRouteHandler.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/JobsRouteHandler.java @@ -79,7 +79,7 @@ public class JobsRouteHandler extends ManagerBase implements RouteHandler { } } - resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found"); + io.notFound(resp, null, outFormat); } protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp, @@ -93,10 +93,10 @@ public class JobsRouteHandler extends ManagerBase implements RouteHandler { protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat, final VeeamControlServlet io) throws IOException { try { - Job response = serverAdapter.getTempJob(id); + Job response = serverAdapter.getJob(id); io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat); } catch (InvalidParameterValueException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat); + io.notFound(resp, e.getMessage(), outFormat); } } } diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/NetworksRouteHandler.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/NetworksRouteHandler.java index d11397e1eee..2450c85cf51 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/NetworksRouteHandler.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/NetworksRouteHandler.java @@ -79,7 +79,7 @@ public class NetworksRouteHandler extends ManagerBase implements RouteHandler { } } - resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found"); + io.notFound(resp, null, outFormat); } protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp, @@ -96,7 +96,7 @@ public class NetworksRouteHandler extends ManagerBase implements RouteHandler { Network response = serverAdapter.getNetwork(id); io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat); } catch (InvalidParameterValueException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat); + io.notFound(resp, e.getMessage(), 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 30d781e868b..103b33b3c6a 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 @@ -32,6 +32,8 @@ import org.apache.cloudstack.veeam.api.dto.DiskAttachment; import org.apache.cloudstack.veeam.api.dto.DiskAttachments; import org.apache.cloudstack.veeam.api.dto.Nic; import org.apache.cloudstack.veeam.api.dto.Nics; +import org.apache.cloudstack.veeam.api.dto.Snapshot; +import org.apache.cloudstack.veeam.api.dto.Snapshots; import org.apache.cloudstack.veeam.api.dto.Vm; import org.apache.cloudstack.veeam.api.dto.VmAction; import org.apache.cloudstack.veeam.api.dto.Vms; @@ -105,7 +107,7 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler { io.methodNotAllowed(resp, "GET, PUT, DELETE", outFormat); } else if ("GET".equalsIgnoreCase(method)) { handleGetById(id, resp, outFormat, io); - } else if ("DELETE".equalsIgnoreCase(method)) { + } else if ("PUT".equalsIgnoreCase(method)) { handleUpdateById(id, req, resp, outFormat, io); } else if ("DELETE".equalsIgnoreCase(method)) { handleDeleteById(id, resp, outFormat, io); @@ -152,11 +154,51 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler { handlePostNicForVmId(id, req, resp, outFormat, io); } return; + } else if ("snapshots".equals(subPath)) { + if (!"GET".equalsIgnoreCase(method) && !"POST".equalsIgnoreCase(method)) { + io.methodNotAllowed(resp, "GET, POST", outFormat); + } else if ("GET".equalsIgnoreCase(method)) { + handleGetSnapshotsByVmId(id, resp, outFormat, io); + } else if ("POST".equalsIgnoreCase(method)) { + handlePostSnapshotForVmId(id, req, resp, outFormat, io); + } + return; + } + } else if (idAndSubPath.size() == 3) { + String subPath = idAndSubPath.get(1); + String subId = idAndSubPath.get(2); + if ("snapshots".equals(subPath)) { + if (!"GET".equalsIgnoreCase(method) && !"DELETE".equalsIgnoreCase(method)) { + io.methodNotAllowed(resp, "GET, DELETE", outFormat); + } else if ("GET".equalsIgnoreCase(method)) { + handleGetSnapshotsById(subId, resp, outFormat, io); + } else if ("DELETE".equalsIgnoreCase(method)) { + handleDeleteSnapshotById(subId, req, resp, outFormat, io); + } + return; + } + } else if (idAndSubPath.size() == 4) { + String subPath = idAndSubPath.get(1); + String subId = idAndSubPath.get(2); + String action = idAndSubPath.get(3); + if ("snapshots".equals(subPath) && "restore".equals(action)) { + if ("POST".equalsIgnoreCase(method)) { + handleRestoreSnapshotById(subId, req, resp, outFormat, io); + } else { + io.methodNotAllowed(resp, "POST", outFormat); + } + return; } } } - resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found"); + io.notFound(resp, null, outFormat); + } + + protected String getRequestData(final HttpServletRequest req) { + String data = RouteHandler.getRequestData(req); + logger.info("Received method: {} request. Request-data: {}", req.getMethod(), data); + return data; } protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp, @@ -192,7 +234,7 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler { return; } - final List result = serverAdapter.listAllUserVms(); + final List result = serverAdapter.listAllInstances(); final Vms response = new Vms(result); io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat); @@ -217,71 +259,76 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler { protected void handlePost(final HttpServletRequest req, final HttpServletResponse resp, Negotiation.OutFormat outFormat, VeeamControlServlet io) throws IOException { - String data = RouteHandler.getRequestData(req); - logger.info("Received method: POST request. Request-data: {}", data); + String data = getRequestData(req); try { Vm request = io.getMapper().jsonMapper().readValue(data, Vm.class); - Vm response = serverAdapter.handleCreateVm(request); + Vm response = serverAdapter.createInstance(request); io.getWriter().write(resp, HttpServletResponse.SC_CREATED, response, outFormat); } catch (JsonProcessingException | CloudRuntimeException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_BAD_REQUEST, "Bad request", e.getMessage(), outFormat); + io.badRequest(resp, e.getMessage(), outFormat); } } protected void handleGetById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat, final VeeamControlServlet io) throws IOException { try { - Vm response = serverAdapter.getVm(id); + Vm response = serverAdapter.getInstance(id); io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat); } catch (InvalidParameterValueException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat); + io.notFound(resp, e.getMessage(), outFormat); } } protected void handleUpdateById(final String id, final HttpServletRequest req, final HttpServletResponse resp, final Negotiation.OutFormat outFormat, final VeeamControlServlet io) throws IOException { String data = RouteHandler.getRequestData(req); - logger.info("Received POST request, but method: POST is not supported atm. Request-data: {}", data); - io.getWriter().writeFault(resp, HttpServletResponse.SC_BAD_REQUEST, "Not implemented", "", outFormat); + logger.info("Received PUT request. Request-data: {}", data); + try { + Vm request = io.getMapper().jsonMapper().readValue(data, Vm.class); + Vm response = serverAdapter.updateInstance(id, request); + io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat); + } catch (InvalidParameterValueException e) { + io.notFound(resp, e.getMessage(), outFormat); + } } protected void handleDeleteById(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat, final VeeamControlServlet io) throws IOException { try { - serverAdapter.deleteVm(id); + serverAdapter.deleteInstance(id); io.getWriter().write(resp, HttpServletResponse.SC_OK, "", outFormat); } catch (CloudRuntimeException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat); + io.notFound(resp, e.getMessage(), outFormat); } } protected void handleStartVmById(final String id, final HttpServletRequest req, final HttpServletResponse resp, final Negotiation.OutFormat outFormat, final VeeamControlServlet io) throws IOException { try { - VmAction vm = serverAdapter.startVm(id); + VmAction vm = serverAdapter.startInstance(id); io.getWriter().write(resp, HttpServletResponse.SC_ACCEPTED, vm, outFormat); } catch (CloudRuntimeException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat); + io.notFound(resp, e.getMessage(), outFormat); } } protected void handleStopVmById(final String id, final HttpServletRequest req, final HttpServletResponse resp, final Negotiation.OutFormat outFormat, final VeeamControlServlet io) throws IOException { try { - VmAction vm = serverAdapter.stopVm(id); + VmAction vm = serverAdapter.stopInstance(id); io.getWriter().write(resp, HttpServletResponse.SC_ACCEPTED, vm, outFormat); } catch (CloudRuntimeException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat); + io.notFound(resp, e.getMessage(), outFormat); } } protected void handleShutdownVmById(final String id, final HttpServletRequest req, final HttpServletResponse resp, final Negotiation.OutFormat outFormat, final VeeamControlServlet io) throws IOException { try { - VmAction vm = serverAdapter.shutdownVm(id); + VmAction vm = serverAdapter.shutdownInstance(id); io.getWriter().write(resp, HttpServletResponse.SC_ACCEPTED, vm, outFormat); } catch (CloudRuntimeException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat); + io.notFound(resp, e.getMessage(), outFormat); } } @@ -292,46 +339,101 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler { DiskAttachments response = new DiskAttachments(disks); io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat); } catch (InvalidParameterValueException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat); + io.notFound(resp, e.getMessage(), outFormat); } } protected void handlePostDiskAttachmentForVmId(final String id, final HttpServletRequest req, final HttpServletResponse resp, final Negotiation.OutFormat outFormat, final VeeamControlServlet io) throws IOException { - String data = RouteHandler.getRequestData(req); - logger.info("Received method: POST request. Request-data: {}", data); + String data = getRequestData(req); try { DiskAttachment request = io.getMapper().jsonMapper().readValue(data, DiskAttachment.class); - DiskAttachment response = serverAdapter.handleVmAttachDisk(id, request); + DiskAttachment response = serverAdapter.handleInstanceAttachDisk(id, request); io.getWriter().write(resp, HttpServletResponse.SC_CREATED, response, outFormat); } catch (JsonProcessingException | CloudRuntimeException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_BAD_REQUEST, "Bad request", e.getMessage(), outFormat); + io.badRequest(resp, e.getMessage(), outFormat); } } protected void handleGetNicsByVmId(final String id, final HttpServletResponse resp, final Negotiation.OutFormat outFormat, final VeeamControlServlet io) throws IOException { try { - List nics = serverAdapter.listNicsByInstanceId(id); + List nics = serverAdapter.listNicsByInstanceUuid(id); Nics response = new Nics(nics); io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat); } catch (InvalidParameterValueException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat); + io.notFound(resp, e.getMessage(), outFormat); } } protected void handlePostNicForVmId(final String id, final HttpServletRequest req, final HttpServletResponse resp, final Negotiation.OutFormat outFormat, final VeeamControlServlet io) throws IOException { - String data = RouteHandler.getRequestData(req); - logger.info("Received method: POST request. Request-data: {}", data); + String data = getRequestData(req); try { Nic request = io.getMapper().jsonMapper().readValue(data, Nic.class); - Nic response = serverAdapter.handleVmAttachNic(id, request); + Nic response = serverAdapter.handleAttachInstanceNic(id, request); io.getWriter().write(resp, HttpServletResponse.SC_CREATED, response, outFormat); } catch (JsonProcessingException | CloudRuntimeException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_BAD_REQUEST, "Bad request", e.getMessage(), outFormat); + io.badRequest(resp, e.getMessage(), outFormat); } } + + protected void handleGetSnapshotsByVmId(final String id, final HttpServletResponse resp, + final Negotiation.OutFormat outFormat, final VeeamControlServlet io) throws IOException { + try { + List snapshots = serverAdapter.listSnapshotsByInstanceUuid(id); + Snapshots response = new Snapshots(snapshots); + io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat); + } catch (InvalidParameterValueException e) { + io.notFound(resp, e.getMessage(), outFormat); + } + } + + protected void handlePostSnapshotForVmId(final String id, final HttpServletRequest req, + final HttpServletResponse resp, final Negotiation.OutFormat outFormat, final VeeamControlServlet io) + throws IOException { + String data = getRequestData(req); + try { + Snapshot request = io.getMapper().jsonMapper().readValue(data, Snapshot.class); + Snapshot response = serverAdapter.handleCreateInstanceSnapshot(id, request); + io.getWriter().write(resp, HttpServletResponse.SC_ACCEPTED, response, outFormat); + } catch (JsonProcessingException | CloudRuntimeException e) { + io.badRequest(resp, e.getMessage(), outFormat); + } + } + + protected void handleGetSnapshotsById(final String id, final HttpServletResponse resp, + final Negotiation.OutFormat outFormat, final VeeamControlServlet io) throws IOException { + try { + Snapshot response = serverAdapter.getSnapshot(id); + io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat); + } catch (InvalidParameterValueException e) { + io.notFound(resp, e.getMessage(), outFormat); + } + } + + protected void handleDeleteSnapshotById(final String id, final HttpServletRequest req, + final HttpServletResponse resp, final Negotiation.OutFormat outFormat, final VeeamControlServlet io) + throws IOException { + boolean async = Boolean.parseBoolean(req.getParameter("async")); + try { + Snapshot snapshot = serverAdapter.deleteSnapshot(id, async); + if (snapshot != null) { + io.getWriter().write(resp, HttpServletResponse.SC_ACCEPTED, null, outFormat); + } else { + io.getWriter().write(resp, HttpServletResponse.SC_ACCEPTED, null, outFormat); + } + } catch (CloudRuntimeException e) { + io.badRequest(resp, e.getMessage(), outFormat); + } + } + + protected void handleRestoreSnapshotById(final String id, final HttpServletRequest req, + final HttpServletResponse resp, final Negotiation.OutFormat outFormat, final VeeamControlServlet io) + throws IOException { + String data = getRequestData(req); + io.badRequest(resp, "Not implemented", outFormat); + } } diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/VnicProfilesRouteHandler.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/VnicProfilesRouteHandler.java index c62fbf69482..a0ce779d644 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/VnicProfilesRouteHandler.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/VnicProfilesRouteHandler.java @@ -79,7 +79,7 @@ public class VnicProfilesRouteHandler extends ManagerBase implements RouteHandle } } - resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found"); + io.notFound(resp, null, outFormat); } protected void handleGet(final HttpServletRequest req, final HttpServletResponse resp, @@ -96,7 +96,7 @@ public class VnicProfilesRouteHandler extends ManagerBase implements RouteHandle VnicProfile response = serverAdapter.getVnicProfile(id); io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat); } catch (InvalidParameterValueException e) { - io.getWriter().writeFault(resp, HttpServletResponse.SC_NOT_FOUND, "Not found", e.getMessage(), outFormat); + io.notFound(resp, e.getMessage(), outFormat); } } } diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/NicVOToNicConverter.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/NicVOToNicConverter.java index 72fe2d55965..204844649ae 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/NicVOToNicConverter.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/NicVOToNicConverter.java @@ -22,6 +22,7 @@ import java.util.function.Function; import java.util.stream.Collectors; import org.apache.cloudstack.veeam.VeeamControlService; +import org.apache.cloudstack.veeam.api.VmsRouteHandler; import org.apache.cloudstack.veeam.api.VnicProfilesRouteHandler; import org.apache.cloudstack.veeam.api.dto.Ip; import org.apache.cloudstack.veeam.api.dto.Ips; @@ -46,10 +47,11 @@ public class NicVOToNicConverter { Mac mac = new Mac(); mac.setAddress(vo.getMacAddress()); nic.setMac(mac); - nic.setLinked(true); - nic.setPlugged(true); - if (StringUtils.isBlank(vmUuid)) { - nic.setVm(Ref.of(basePath + "/vms/" + vmUuid, vmUuid)); + nic.setLinked(Boolean.TRUE.toString()); + nic.setPlugged(Boolean.TRUE.toString()); + nic.setSynced(Boolean.TRUE.toString()); + if (StringUtils.isNotBlank(vmUuid)) { + nic.setVm(Ref.of(basePath + VmsRouteHandler.BASE_ROUTE + "/" + vmUuid, vmUuid)); nic.setHref(nic.getVm().href + "/nics/" + vo.getUuid()); } nic.setInterfaceType("virtio"); @@ -70,6 +72,7 @@ public class NicVOToNicConverter { device.setType("network"); device.setId(vo.getUuid()); device.setName("eth0"); + device.setDescription(String.format("%s device", vo.getReserver())); device.setMac(mac); Ip ip = new Ip(); if (vo.getIPv4Address() != null) { @@ -82,6 +85,7 @@ public class NicVOToNicConverter { ip.setVersion("v6"); } device.setIps(new Ips(List.of(ip))); + device.setHref(vm.href + "/reporteddevices/" + vo.getUuid()); device.setVm(vm); return device; } 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 a4f59dfee52..15d7071e959 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 @@ -28,12 +28,12 @@ import org.apache.cloudstack.veeam.api.ApiService; import org.apache.cloudstack.veeam.api.JobsRouteHandler; import org.apache.cloudstack.veeam.api.VmsRouteHandler; import org.apache.cloudstack.veeam.api.dto.Actions; +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.DiskAttachments; import org.apache.cloudstack.veeam.api.dto.EmptyElement; -import org.apache.cloudstack.veeam.api.dto.Link; import org.apache.cloudstack.veeam.api.dto.Nic; import org.apache.cloudstack.veeam.api.dto.Nics; import org.apache.cloudstack.veeam.api.dto.Os; @@ -71,6 +71,7 @@ public final class UserVmJoinVOToVmConverter { dst.description = src.getDisplayName(); dst.href = basePath + VmsRouteHandler.BASE_ROUTE + "/" + src.getUuid(); dst.status = mapStatus(src.getState()); + dst.setCreationTime(src.getCreated().getTime()); final Date lastUpdated = src.getLastUpdated() != null ? src.getLastUpdated() : src.getCreated(); if ("down".equals(dst.status)) { dst.stopTime = lastUpdated.getTime(); @@ -106,7 +107,7 @@ public final class UserVmJoinVOToVmConverter { } } - dst.memory = src.getRamSize() * 1024L * 1024L; + dst.memory = String.valueOf(src.getRamSize() * 1024L * 1024L); dst.cpu = new Cpu(src.getArch(), new Topology(src.getCpu(), 1, 1)); dst.os = new Os(); @@ -129,17 +130,15 @@ public final class UserVmJoinVOToVmConverter { } dst.actions = new Actions(List.of( - new Link("start", dst.href + "/start"), - new Link("stop", dst.href + "/stop"), - new Link("shutdown", dst.href + "/shutdown") + BaseDto.getActionLink("start", dst.href), + BaseDto.getActionLink("stop", dst.href), + BaseDto.getActionLink("shutdown", dst.href) )); dst.link = List.of( - new Link("diskattachments", - dst.href + "/diskattachments"), - new Link("nics", - dst.href + "/nics"), - new Link("snapshots", - dst.href + "/snapshots") + BaseDto.getActionLink("diskattachments", dst.href), + BaseDto.getActionLink("nics", dst.href), + BaseDto.getActionLink("reporteddevices", dst.href), + BaseDto.getActionLink("snapshots", dst.href) ); dst.tags = new EmptyElement(); @@ -162,21 +161,12 @@ public final class UserVmJoinVOToVmConverter { } private static String mapStatus(final VirtualMachine.State state) { - if (state == null) { - return null; - } - // CloudStack-ish states -> oVirt-ish up/down if (Arrays.asList(VirtualMachine.State.Running, VirtualMachine.State.Starting, VirtualMachine.State.Migrating, VirtualMachine.State.Restoring).contains(state)) { return "up"; } - if (Arrays.asList(VirtualMachine.State.Stopped, VirtualMachine.State.Stopping, - VirtualMachine.State.Shutdown, VirtualMachine.State.Error, - VirtualMachine.State.Expunging).contains(state)) { - return "down"; - } - return null; + return "down"; } private static Ref buildRef(final String baseHref, final String suffix, final String id) { diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/VmSnapshotVOToSnapshotConverter.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/VmSnapshotVOToSnapshotConverter.java new file mode 100644 index 00000000000..cf7226227b0 --- /dev/null +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/VmSnapshotVOToSnapshotConverter.java @@ -0,0 +1,54 @@ +// 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.VmsRouteHandler; +import org.apache.cloudstack.veeam.api.dto.Actions; +import org.apache.cloudstack.veeam.api.dto.BaseDto; +import org.apache.cloudstack.veeam.api.dto.Ref; +import org.apache.cloudstack.veeam.api.dto.Snapshot; + +import com.cloud.vm.snapshot.VMSnapshot; +import com.cloud.vm.snapshot.VMSnapshotVO; + +public class VmSnapshotVOToSnapshotConverter { + public static Snapshot toSnapshot(final VMSnapshotVO vmSnapshotVO, String vmUuid) { + final String basePath = VeeamControlService.ContextPath.value(); + final Snapshot snapshot = new Snapshot(); + snapshot.setId(vmSnapshotVO.getUuid()); + snapshot.setHref(basePath + VmsRouteHandler.BASE_ROUTE + "/" + vmUuid + "/snapshots/" + vmSnapshotVO.getUuid()); + snapshot.setVm(Ref.of(basePath + VmsRouteHandler.BASE_ROUTE + "/" + vmUuid, vmUuid)); + snapshot.setDescription(vmSnapshotVO.getDescription()); + snapshot.setSnapshotType("active"); + snapshot.setDate(vmSnapshotVO.getCreated().getTime()); + snapshot.setPersistMemorystate(String.valueOf(VMSnapshotVO.Type.DiskAndMemory.equals(vmSnapshotVO.getType()))); + snapshot.setSnapshotStatus(VMSnapshot.State.Ready.equals(vmSnapshotVO.getState()) ? "ok" : "locked"); + snapshot.setActions(new Actions(List.of(BaseDto.getActionLink("restore", snapshot.getHref())))); + return snapshot; + } + + public static List toSnapshotList(final List vmSnapshotVOList, final String vmUuid) { + return vmSnapshotVOList.stream() + .map(v -> toSnapshot(v, vmUuid)) + .collect(Collectors.toList()); + } +} 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 index 0bb8e40d92a..015b0076334 100644 --- 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 @@ -40,13 +40,14 @@ import com.cloud.storage.VolumeStats; public class VolumeJoinVOToDiskConverter { public static Disk toDisk(final VolumeJoinVO vol) { final Disk disk = new Disk(); - final String basePath = VeeamControlService.ContextPath.value() + ApiService.BASE_ROUTE; - + final String basePath = VeeamControlService.ContextPath.value(); + final String apiBasePath = basePath + ApiService.BASE_ROUTE; final String diskId = vol.getUuid(); final String diskHref = basePath + DisksRouteHandler.BASE_ROUTE + "/" + diskId; disk.id = diskId; disk.href = diskHref; + disk.setBootable(String.valueOf(Volume.Type.ROOT.equals(vol.getVolumeType()))); // Names disk.name = vol.getName(); @@ -98,7 +99,7 @@ public class VolumeJoinVOToDiskConverter { // Disk profile (optional) disk.diskProfile = Ref.of( - basePath + "/diskprofiles/" + vol.getDiskOfferingUuid(), + apiBasePath + "/diskprofiles/" + vol.getDiskOfferingUuid(), String.valueOf(vol.getDiskOfferingUuid()) ); @@ -107,7 +108,7 @@ public class VolumeJoinVOToDiskConverter { Disk.StorageDomains sds = new Disk.StorageDomains(); sds.storageDomain = List.of( Ref.of( - basePath + "/storagedomains/" + vol.getPoolUuid(), + apiBasePath + "/storagedomains/" + vol.getPoolUuid(), vol.getPoolUuid() ) ); @@ -134,7 +135,6 @@ public class VolumeJoinVOToDiskConverter { public static DiskAttachment toDiskAttachment(final VolumeJoinVO vol) { final DiskAttachment da = new DiskAttachment(); final String basePath = VeeamControlService.ContextPath.value(); - final String apiBase = basePath + ApiService.BASE_ROUTE; final String diskAttachmentId = vol.getUuid(); da.vm = Ref.of( @@ -143,7 +143,7 @@ public class VolumeJoinVOToDiskConverter { ); da.id = diskAttachmentId; - da.href = da.vm.href + "/diskattachements/" + diskAttachmentId;; + da.href = da.vm.href + "/diskattachments/" + diskAttachmentId;; // Links da.disk = toDisk(vol); diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/BaseDto.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/BaseDto.java new file mode 100644 index 00000000000..013dd9145d9 --- /dev/null +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/BaseDto.java @@ -0,0 +1,47 @@ +// 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 BaseDto { + + private String href; + private String id; + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public static Link getActionLink(final String action, final String baseHref) { + return new Link(action, baseHref + "/" + action); + } +} 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 index f61cd5d890e..6ba2f1d736b 100644 --- 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 @@ -28,6 +28,8 @@ import java.util.List; @JacksonXmlRootElement(localName = "disk") public final class Disk { + private String bootable; + @JsonProperty("actual_size") public String actualSize; @@ -88,6 +90,14 @@ public final class Disk { public Disk() {} + public String getBootable() { + return bootable; + } + + public void setBootable(String bootable) { + this.bootable = bootable; + } + @JsonInclude(JsonInclude.Include.NON_NULL) @JacksonXmlRootElement(localName = "storage_domains") public static final class StorageDomains { diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Nic.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Nic.java index 7eca9aff4f7..dcb9d3505a3 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Nic.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Nic.java @@ -34,6 +34,7 @@ public class Nic { private String linked; private Mac mac; private String plugged; + public String synced; private Ref vnicProfile; private Ref vm; private ReportedDevices reportedDevices; @@ -81,12 +82,12 @@ public class Nic { this.interfaceType = interfaceType; } - public boolean isLinked() { - return Boolean.parseBoolean(linked); + public String getLinked() { + return linked; } - public void setLinked(boolean linked) { - this.linked = Boolean.toString(linked); + public void setLinked(String linked) { + this.linked = linked; } public Mac getMac() { @@ -97,12 +98,20 @@ public class Nic { this.mac = mac; } - public boolean isPlugged() { - return Boolean.parseBoolean(plugged); + public String getPlugged() { + return plugged; } - public void setPlugged(boolean plugged) { - this.plugged = Boolean.toString(plugged); + public void setPlugged(String plugged) { + this.plugged = plugged; + } + + public String getSynced() { + return synced; + } + + public void setSynced(String synced) { + this.synced = synced; } public Ref getVnicProfile() { diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/ReportedDevice.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/ReportedDevice.java index 7c36f2d02f5..14a540699bb 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/ReportedDevice.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/ReportedDevice.java @@ -25,6 +25,7 @@ public class ReportedDevice { private Mac Mac; private String name; private String type; + private String href; private Ref vm; public String getComment() { @@ -83,6 +84,14 @@ public class ReportedDevice { this.type = type; } + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } + public Ref getVm() { return vm; } diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Snapshot.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Snapshot.java new file mode 100644 index 00000000000..5f5347e1181 --- /dev/null +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Snapshot.java @@ -0,0 +1,104 @@ +// 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.dataformat.xml.annotation.JacksonXmlElementWrapper; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Snapshot extends BaseDto { + + // epoch millis + private Long date; + private String persistMemorystate; + private String snapshotStatus; + private String snapshotType; + private Actions actions; + private String description; + @JacksonXmlElementWrapper(useWrapping = false) + private List link; + private Ref vm; + + public Snapshot() {} + + public Long getDate() { + return date; + } + + public void setDate(final Long date) { + this.date = date; + } + + public String getPersistMemorystate() { + return persistMemorystate; + } + + public void setPersistMemorystate(final String persistMemorystate) { + this.persistMemorystate = persistMemorystate; + } + + public String getSnapshotStatus() { + return snapshotStatus; + } + + public void setSnapshotStatus(final String snapshotStatus) { + this.snapshotStatus = snapshotStatus; + } + + public String getSnapshotType() { + return snapshotType; + } + + public void setSnapshotType(final String snapshotType) { + this.snapshotType = snapshotType; + } + + public Actions getActions() { + return actions; + } + + public void setActions(final Actions actions) { + this.actions = actions; + } + + public String getDescription() { + return description; + } + + public void setDescription(final String description) { + this.description = description; + } + + public List getLink() { + return link; + } + + public void setLink(final List link) { + this.link = link; + } + + public Ref getVm() { + return vm; + } + + public void setVm(Ref vm) { + this.vm = vm; + } +} diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Snapshots.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Snapshots.java new file mode 100644 index 00000000000..66a9b93e46d --- /dev/null +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Snapshots.java @@ -0,0 +1,41 @@ +// 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 = "snapshots") +public final class Snapshots { + + @JsonProperty("snapshot") + @JacksonXmlElementWrapper(useWrapping = false) + public List snapshot; + + public Snapshots() {} + + public Snapshots(final List snapshot) { + this.snapshot = snapshot; + } +} + 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 c83a7536e6a..2438109105f 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 @@ -43,6 +43,8 @@ public final class Vm { @JacksonXmlProperty(localName = "stop_reason") public String stopReason; // empty string allowed + private Long creationTime; + @JsonProperty("stop_time") @JacksonXmlProperty(localName = "stop_time") public Long stopTime; // epoch millis @@ -57,7 +59,7 @@ public final class Vm { public Ref cluster; public Ref host; - public Long memory; // bytes + public String memory; // bytes public Cpu cpu; public Os os; public Bios bios; @@ -77,6 +79,14 @@ public final class Vm { public Vm() {} + public Long getCreationTime() { + return creationTime; + } + + public void setCreationTime(Long creationTime) { + this.creationTime = creationTime; + } + public Long getStartTime() { return startTime; } diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/VmInitialization.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/VmInitialization.java index 61982872afc..a9e77b01a1c 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/VmInitialization.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/VmInitialization.java @@ -22,13 +22,13 @@ import com.fasterxml.jackson.annotation.JsonInclude; @JsonInclude(JsonInclude.Include.NON_NULL) public class VmInitialization { - private String contentData; + private String customScript; - public String getContentData() { - return contentData; + public String getCustomScript() { + return customScript; } - public void setContentData(String contentData) { - this.contentData = contentData; + public void setCustomScript(String customScript) { + this.customScript = customScript; } } diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/services/PkiResourceRouteHandler.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/services/PkiResourceRouteHandler.java index 19b1b88d7f3..0e2037ba9db 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/services/PkiResourceRouteHandler.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/services/PkiResourceRouteHandler.java @@ -65,7 +65,7 @@ public class PkiResourceRouteHandler extends ManagerBase implements RouteHandler return; } - resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found"); + io.notFound(resp, null, outFormat); } protected void handleGet(HttpServletRequest req, HttpServletResponse resp, diff --git a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/sso/SsoService.java b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/sso/SsoService.java index c8066823999..26a29d6d531 100644 --- a/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/sso/SsoService.java +++ b/plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/sso/SsoService.java @@ -55,7 +55,7 @@ public class SsoService extends ManagerBase implements RouteHandler { return; } - resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Not found"); + io.notFound(resp, null, outFormat); } protected void handleToken(HttpServletRequest req, HttpServletResponse resp,