plugin changes, fixes

Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
This commit is contained in:
Abhishek Kumar 2026-02-17 17:48:03 +05:30
parent 0b4b02da63
commit c0b8aa636a
9 changed files with 134 additions and 102 deletions

View File

@ -24,6 +24,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@ -37,6 +38,7 @@ import org.apache.cloudstack.acl.Rule;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiServerService;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.command.admin.backup.DeleteVmCheckpointCmd;
import org.apache.cloudstack.api.command.admin.backup.FinalizeBackupCmd;
import org.apache.cloudstack.api.command.admin.backup.StartBackupCmd;
import org.apache.cloudstack.api.command.admin.vm.DeployVMCmdByAdmin;
@ -84,6 +86,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.UserVmVOToCheckpointConverter;
import org.apache.cloudstack.veeam.api.converter.VmSnapshotVOToSnapshotConverter;
import org.apache.cloudstack.veeam.api.converter.VolumeJoinVOToDiskConverter;
import org.apache.cloudstack.veeam.api.dto.Backup;
@ -442,7 +445,7 @@ public class ServerAdapter extends ManagerBase {
}
Integer cpu = null;
try {
cpu = request.getCpu().getTopology().getSockets();
cpu = Integer.valueOf(request.getCpu().getTopology().getSockets());
} catch (Exception ignored) {}
if (cpu == null) {
throw new InvalidParameterValueException("CPU topology sockets must be specified");
@ -1078,9 +1081,8 @@ public class ServerAdapter extends ManagerBase {
if (vmVo == null) {
throw new InvalidParameterValueException("VM with ID " + vmUuid + " not found");
}
// Register a context as resource owner
Account account = accountService.getAccount(vmVo.getAccountId());
CallContext ctx = CallContext.register(vmVo.getUserId(), vmVo.getAccountId());
Pair<User, Account> serviceUserAccount = createServiceAccountIfNeeded();
CallContext ctx = CallContext.register(serviceUserAccount.first(), serviceUserAccount.second());
try {
StartBackupCmd cmd = new StartBackupCmd();
ComponentContext.inject(cmd);
@ -1089,8 +1091,8 @@ public class ServerAdapter extends ManagerBase {
params.put(ApiConstants.NAME, request.getName());
params.put(ApiConstants.DESCRIPTION, request.getDescription());
ApiServerService.AsyncCmdResult result =
apiServerService.processAsyncCmd(cmd, params, ctx, vmVo.getUserId(), account);
if (result.objectId == null) {
apiServerService.processAsyncCmd(cmd, params, ctx, vmVo.getUserId(), serviceUserAccount.second());
if (result == null || result.objectId == null) {
throw new CloudRuntimeException("Unexpected backup ID returned");
}
BackupVO vo = backupDao.findById(result.objectId);
@ -1169,14 +1171,16 @@ public class ServerAdapter extends ManagerBase {
throw new InvalidParameterValueException("Backup with ID " + backupUuid + " not found");
}
Pair<User, Account> serviceUserAccount = createServiceAccountIfNeeded();
CallContext.register(serviceUserAccount.first(), serviceUserAccount.second());
CallContext ctx = CallContext.register(serviceUserAccount.first(), serviceUserAccount.second());
try {
FinalizeBackupCmd cmd = new FinalizeBackupCmd();
ComponentContext.inject(cmd);
cmd.setBackupId(backup.getId());
cmd.setVmId(vm.getId());
boolean result = incrementalBackupService.finalizeBackup(cmd);
if (!result) {
Map<String, String> params = new HashMap<>();
params.put(ApiConstants.VIRTUAL_MACHINE_ID, vm.getUuid());
params.put(ApiConstants.ID, backup.getUuid());
ApiServerService.AsyncCmdResult result =
apiServerService.processAsyncCmd(cmd, params, ctx, vm.getUserId(), serviceUserAccount.second());
if (result == null) {
throw new CloudRuntimeException("Failed to finalize backup");
}
backup = backupDao.findById(backup.getId());
@ -1197,42 +1201,37 @@ public class ServerAdapter extends ManagerBase {
}
public List<Checkpoint> listCheckpointsByInstanceUuid(final String uuid) {
throw new InvalidParameterValueException("Checkpoints for VM with ID " + uuid + " not implemented");
// UserVmVO vo = userVmDao.findByUuid(uuid);
// if (vo == null) {
// throw new InvalidParameterValueException("VM with ID " + uuid + " not found");
// }
// List<CheckpointVO> checkpoints = checkpointDao.findByVmId(vo.getId());
// return CheckpointVOToCheckpointConverter.toCheckpointList(checkpoints, vo.getUuid());
UserVmVO vo = userVmDao.findByUuid(uuid);
if (vo == null) {
throw new InvalidParameterValueException("VM with ID " + uuid + " not found");
}
Checkpoint checkpoint = UserVmVOToCheckpointConverter.toCheckpoint(vo);
if (checkpoint == null) {
return Collections.emptyList();
}
return List.of(checkpoint);
}
public ResourceAction deleteCheckpoint(String uuid, boolean async) {
throw new InvalidParameterValueException("Delete Checkpoint with ID " + uuid + " not implemented");
// ResourceAction action = null;
// CheckpointVO vo = checkpointDao.findByUuid(uuid);
// if (vo == null) {
// throw new InvalidParameterValueException("Checkpoint with ID " + uuid + " not found");
// }
// Pair<User, Account> serviceUserAccount = createServiceAccountIfNeeded();
// CallContext ctx = CallContext.register(serviceUserAccount.first(), serviceUserAccount.second());
// try {
// DeleteCheckpointCmd cmd = new DeleteCheckpointCmd();
// ComponentContext.inject(cmd);
// Map<String, String> params = new HashMap<>();
// params.put(ApiConstants.CHECKPOINT_ID, vo.getUuid());
// ApiServerService.AsyncCmdResult result =
// apiServerService.processAsyncCmd(cmd, params, ctx, serviceUserAccount.first().getId(),
// serviceUserAccount.second());
// AsyncJobJoinVO jobVo = asyncJobJoinDao.findById(result.jobId);
// if (jobVo == null) {
// throw new CloudRuntimeException("Failed to find job for checkpoint deletion");
// }
// action = AsyncJobJoinVOToJobConverter.toAction(jobVo);
// } catch (Exception e) {
// throw new CloudRuntimeException("Failed to delete checkpoint: " + e.getMessage(), e);
// } finally {
// CallContext.unregister();
// }
// return action;
public void deleteCheckpoint(String vmUuid, String checkpointId) {
UserVmVO vo = userVmDao.findByUuid(vmUuid);
if (vo == null) {
throw new InvalidParameterValueException("VM with ID " + vmUuid + " not found");
}
if (!Objects.equals(vo.getActiveCheckpointId(), checkpointId)) {
logger.warn("Checkpoint ID {} does not match active checkpoint for VM {}", checkpointId, vmUuid);
return;
}
Pair<User, Account> serviceUserAccount = createServiceAccountIfNeeded();
CallContext.register(serviceUserAccount.first(), serviceUserAccount.second());
try {
DeleteVmCheckpointCmd cmd = new DeleteVmCheckpointCmd();
ComponentContext.inject(cmd);
cmd.setVmId(vo.getId());
incrementalBackupService.deleteVmCheckpoint(cmd);
} catch (Exception e) {
throw new CloudRuntimeException("Failed to delete checkpoint: " + e.getMessage(), e);
} finally {
CallContext.unregister();
}
}
}

View File

@ -30,7 +30,6 @@ import org.apache.cloudstack.veeam.VeeamControlServlet;
import org.apache.cloudstack.veeam.adapter.ServerAdapter;
import org.apache.cloudstack.veeam.api.dto.Backup;
import org.apache.cloudstack.veeam.api.dto.Checkpoint;
import org.apache.cloudstack.veeam.api.dto.Checkpoints;
import org.apache.cloudstack.veeam.api.dto.Disk;
import org.apache.cloudstack.veeam.api.dto.DiskAttachment;
import org.apache.cloudstack.veeam.api.dto.DiskAttachments;
@ -208,7 +207,7 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler {
return;
} else if ("checkpoints".equals(subPath)) {
if ("DELETE".equalsIgnoreCase(method)) {
handleDeleteCheckpointById(subId, req, resp, outFormat, io);
handleDeleteCheckpoint(id, subId, resp, outFormat, io);
} else {
io.methodNotAllowed(resp, "DELETE", outFormat);
}
@ -545,25 +544,19 @@ public class VmsRouteHandler extends ManagerBase implements RouteHandler {
final Negotiation.OutFormat outFormat, final VeeamControlServlet io) throws IOException {
try {
List<Checkpoint> checkpoints = serverAdapter.listCheckpointsByInstanceUuid(id);
Checkpoints response = new Checkpoints(checkpoints);
NamedList<Checkpoint> response = NamedList.of("checkpoints", checkpoints);
io.getWriter().write(resp, HttpServletResponse.SC_OK, response, outFormat);
} catch (InvalidParameterValueException e) {
io.notFound(resp, e.getMessage(), outFormat);
}
}
protected void handleDeleteCheckpointById(final String id, final HttpServletRequest req,
protected void handleDeleteCheckpoint(final String vmId, final String checkpointId,
final HttpServletResponse resp, final Negotiation.OutFormat outFormat, final VeeamControlServlet io)
throws IOException {
String asyncStr = req.getParameter("async");
boolean async = !Boolean.FALSE.toString().equals(asyncStr);
try {
ResourceAction action = serverAdapter.deleteCheckpoint(id, async);
if (action != null) {
io.getWriter().write(resp, HttpServletResponse.SC_ACCEPTED, action, outFormat);
} else {
io.getWriter().write(resp, HttpServletResponse.SC_OK, null, outFormat);
}
serverAdapter.deleteCheckpoint(vmId, checkpointId);
io.getWriter().write(resp, HttpServletResponse.SC_OK, null, outFormat);
} catch (CloudRuntimeException e) {
io.badRequest(resp, e.getMessage(), outFormat);
}

View File

@ -66,7 +66,7 @@ public class HostJoinVOToHostConverter {
// --- CPU ---
final Cpu cpu = new Cpu();
cpu.setSpeed(Math.toIntExact(vo.getSpeed()));
cpu.setSpeed(String.valueOf(Math.toIntExact(vo.getSpeed())));
final Topology topo = new Topology(vo.getCpuSockets(), vo.getCpus(), 1);
cpu.setTopology(topo);
h.setCpu(cpu);

View File

@ -32,6 +32,7 @@ import org.apache.cloudstack.veeam.api.dto.Ref;
import org.apache.cloudstack.veeam.api.dto.ReportedDevice;
import org.apache.cloudstack.veeam.api.dto.ReportedDevices;
import org.apache.cloudstack.veeam.api.dto.Vm;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
@ -76,17 +77,19 @@ public class NicVOToNicConverter {
device.setName("eth0");
device.setDescription(String.format("%s device", vo.getReserver()));
device.setMac(mac);
Ip ip = new Ip();
if (vo.getIPv4Address() != null) {
ip.setAddress(vo.getIPv4Address());
ip.setGateway(vo.getIPv4Gateway());
ip.setVersion("v4");
} else if (vo.getIPv6Address() != null) {
ip.setAddress(vo.getIPv6Address());
ip.setGateway(vo.getIPv6Gateway());
ip.setVersion("v6");
if (ObjectUtils.anyNotNull(vo.getIPv4Address(), vo.getIPv6Address())) {
Ip ip = new Ip();
if (vo.getIPv4Address() != null) {
ip.setAddress(vo.getIPv4Address());
ip.setGateway(vo.getIPv4Gateway());
ip.setVersion("v4");
} else if (vo.getIPv6Address() != null) {
ip.setAddress(vo.getIPv6Address());
ip.setGateway(vo.getIPv6Gateway());
ip.setVersion("v6");
}
device.setIps(new Ips(List.of(ip)));
}
device.setIps(new Ips(List.of(ip)));
device.setHref(vm.getHref() + "/reporteddevices/" + vo.getUuid());
device.setVm(vm);
return device;

View File

@ -25,7 +25,6 @@ import java.util.stream.Collectors;
import org.apache.cloudstack.veeam.VeeamControlService;
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;
@ -40,7 +39,6 @@ import org.apache.cloudstack.veeam.api.dto.Os;
import org.apache.cloudstack.veeam.api.dto.Ref;
import org.apache.cloudstack.veeam.api.dto.Topology;
import org.apache.cloudstack.veeam.api.dto.Vm;
import org.apache.cloudstack.veeam.api.dto.VmAction;
import org.apache.commons.lang3.StringUtils;
import com.cloud.api.query.vo.HostJoinVO;
@ -156,15 +154,6 @@ public final class UserVmJoinVOToVmConverter {
.collect(Collectors.toList());
}
public static VmAction toVmAction(final UserVmJoinVO vm) {
VmAction action = new VmAction();
final String basePath = VeeamControlService.ContextPath.value();
action.setVm(toVm(vm, null, null, null));
action.setJob(Ref.of(basePath + JobsRouteHandler.BASE_ROUTE + vm.getUuid(), vm.getUuid()));
action.setStatus("complete");
return action;
}
private static String mapStatus(final VirtualMachine.State state) {
// CloudStack-ish states -> oVirt-ish up/down
if (Arrays.asList(VirtualMachine.State.Running,

View File

@ -0,0 +1,45 @@
// 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.time.Instant;
import org.apache.cloudstack.veeam.api.dto.Checkpoint;
import org.apache.commons.lang3.StringUtils;
import com.cloud.vm.UserVmVO;
public class UserVmVOToCheckpointConverter {
public static Checkpoint toCheckpoint(final UserVmVO vm) {
if (StringUtils.isEmpty(vm.getActiveCheckpointId())) {
return null;
}
Checkpoint checkpoint = new Checkpoint();
checkpoint.setId(vm.getActiveCheckpointId());
checkpoint.setName(vm.getActiveCheckpointId());
Long createTimeSeconds = vm.getActiveCheckpointCreateTime();
if (createTimeSeconds != null) {
checkpoint.setCreationDate(String.valueOf(Instant.ofEpochSecond(createTimeSeconds).toEpochMilli()));
} else {
checkpoint.setCreationDate(String.valueOf(System.currentTimeMillis()));
}
checkpoint.setState("created");
return checkpoint;
}
}

View File

@ -22,15 +22,15 @@ import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL)
public final class Cpu {
private String name;
private Integer speed;
private String speed;
private String architecture;
private String type;
private Topology topology;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Integer getSpeed() { return speed; }
public void setSpeed(Integer speed) { this.speed = speed; }
public String getSpeed() { return speed; }
public void setSpeed(String speed) { this.speed = speed; }
public String getArchitecture() { return architecture; }
public void setArchitecture(String architecture) { this.architecture = architecture; }
public String getType() { return type; }

View File

@ -22,19 +22,22 @@ import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL)
public final class SummaryCount {
private Integer active;
private Integer total;
private String active;
private String total;
public SummaryCount(Integer active, Integer total) {
this.active = active;
this.total = total;
public SummaryCount() {
}
public Integer getActive() {
public SummaryCount(Integer active, Integer total) {
this.active = String.valueOf(active);
this.total = String.valueOf(total);
}
public String getActive() {
return active;
}
public Integer getTotal() {
public String getTotal() {
return total;
}
}

View File

@ -21,40 +21,40 @@ import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL)
public final class Topology {
public Integer sockets;
public Integer cores;
public Integer threads;
public String sockets;
public String cores;
public String threads;
public Topology() {
}
public Topology(final Integer sockets, final Integer cores, final Integer threads) {
this.sockets = sockets;
this.cores = cores;
this.threads = threads;
this.sockets = String.valueOf(sockets);
this.cores = String.valueOf(cores);
this.threads = String.valueOf(threads);
}
public Integer getSockets() {
public String getSockets() {
return sockets;
}
public void setSockets(Integer sockets) {
public void setSockets(String sockets) {
this.sockets = sockets;
}
public Integer getCores() {
public String getCores() {
return cores;
}
public void setCores(Integer cores) {
public void setCores(String cores) {
this.cores = cores;
}
public Integer getThreads() {
public String getThreads() {
return threads;
}
public void setThreads(Integer threads) {
public void setThreads(String threads) {
this.threads = threads;
}
}