mirror of https://github.com/apache/cloudstack.git
move checkpoint to vm details
This commit is contained in:
parent
d6055c9ae2
commit
b84ff6b99a
|
|
@ -130,4 +130,10 @@ public interface VmDetailConstants {
|
|||
String EXTERNAL_DETAIL_PREFIX = "External:";
|
||||
String CLOUDSTACK_VM_DETAILS = "cloudstack.vm.details";
|
||||
String CLOUDSTACK_VLAN = "cloudstack.vlan";
|
||||
|
||||
// KVM Checkpoints related
|
||||
String ACTIVE_CHECKPOINT_ID = "active.checkpoint.id";
|
||||
String ACTIVE_CHECKPOINT_CREATE_TIME = "active.checkpoint.create.time";
|
||||
String LAST_CHECKPOINT_ID = "last.checkpoint.id";
|
||||
String LAST_CHECKPOINT_CREATE_TIME = "last.checkpoint.create.time";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import com.cloud.agent.api.Answer;
|
|||
|
||||
public class StartBackupAnswer extends Answer {
|
||||
private Long checkpointCreateTime;
|
||||
private Boolean isIncremental;
|
||||
|
||||
public StartBackupAnswer() {
|
||||
}
|
||||
|
|
@ -42,12 +41,4 @@ public class StartBackupAnswer extends Answer {
|
|||
public void setCheckpointCreateTime(Long checkpointCreateTime) {
|
||||
this.checkpointCreateTime = checkpointCreateTime;
|
||||
}
|
||||
|
||||
public Boolean getIncremental() {
|
||||
return isIncremental;
|
||||
}
|
||||
|
||||
public void setIncremental(Boolean incremental) {
|
||||
isIncremental = incremental;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -202,12 +202,6 @@ public class VMInstanceVO implements VirtualMachine, FiniteStateObject<State, Vi
|
|||
@Column(name = "backup_volumes", length = 65535)
|
||||
protected String backupVolumes;
|
||||
|
||||
@Column(name = "active_checkpoint_id")
|
||||
protected String activeCheckpointId;
|
||||
|
||||
@Column(name = "active_checkpoint_create_time")
|
||||
protected Long activeCheckpointCreateTime;
|
||||
|
||||
public VMInstanceVO(long id, long serviceOfferingId, String name, String instanceName, Type type, Long vmTemplateId, HypervisorType hypervisorType, long guestOSId,
|
||||
long domainId, long accountId, long userId, boolean haEnabled) {
|
||||
this.id = id;
|
||||
|
|
@ -634,20 +628,4 @@ public class VMInstanceVO implements VirtualMachine, FiniteStateObject<State, Vi
|
|||
public void setBackupVolumes(String backupVolumes) {
|
||||
this.backupVolumes = backupVolumes;
|
||||
}
|
||||
|
||||
public String getActiveCheckpointId() {
|
||||
return activeCheckpointId;
|
||||
}
|
||||
|
||||
public void setActiveCheckpointId(String activeCheckpointId) {
|
||||
this.activeCheckpointId = activeCheckpointId;
|
||||
}
|
||||
|
||||
public Long getActiveCheckpointCreateTime() {
|
||||
return activeCheckpointCreateTime;
|
||||
}
|
||||
|
||||
public void setActiveCheckpointCreateTime(Long activeCheckpointCreateTime) {
|
||||
this.activeCheckpointCreateTime = activeCheckpointCreateTime;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,10 +124,6 @@ CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.backups', 'to_checkpoint_id', 'VARCH
|
|||
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.backups', 'checkpoint_create_time', 'BIGINT DEFAULT NULL COMMENT "Checkpoint creation timestamp from libvirt"');
|
||||
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.backups', 'host_id', 'BIGINT UNSIGNED DEFAULT NULL COMMENT "Host where backup is running"');
|
||||
|
||||
-- Add checkpoint tracking fields to vm_instance table for domain recreation
|
||||
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vm_instance', 'active_checkpoint_id', 'VARCHAR(255) DEFAULT NULL COMMENT "Active checkpoint id tracked for incremental backups"');
|
||||
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vm_instance', 'active_checkpoint_create_time', 'BIGINT DEFAULT NULL COMMENT "Active checkpoint creation time"');
|
||||
|
||||
-- Create image_transfer table for per-disk image transfers
|
||||
CREATE TABLE IF NOT EXISTS `cloud`.`image_transfer`(
|
||||
`id` bigint unsigned NOT NULL auto_increment COMMENT 'id',
|
||||
|
|
|
|||
|
|
@ -1686,7 +1686,10 @@ public class ServerAdapter extends ManagerBase {
|
|||
throw new InvalidParameterValueException("VM with ID " + uuid + " not found");
|
||||
}
|
||||
accountService.checkAccess(CallContext.current().getCallingAccount(), null, false, vo);
|
||||
Checkpoint checkpoint = UserVmVOToCheckpointConverter.toCheckpoint(vo);
|
||||
Map<String, String> details = vmInstanceDetailsDao.listDetailsKeyPairs(vo.getId());
|
||||
Checkpoint checkpoint = UserVmVOToCheckpointConverter.toCheckpoint(
|
||||
details.get(VmDetailConstants.ACTIVE_CHECKPOINT_ID),
|
||||
details.get(VmDetailConstants.ACTIVE_CHECKPOINT_CREATE_TIME));
|
||||
if (checkpoint == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
|
@ -1700,7 +1703,8 @@ public class ServerAdapter extends ManagerBase {
|
|||
throw new InvalidParameterValueException("VM with ID " + vmUuid + " not found");
|
||||
}
|
||||
accountService.checkAccess(CallContext.current().getCallingAccount(), SecurityChecker.AccessType.OperateEntry, false, vo);
|
||||
if (!Objects.equals(vo.getActiveCheckpointId(), checkpointId)) {
|
||||
Map<String, String> details = vmInstanceDetailsDao.listDetailsKeyPairs(vo.getId());
|
||||
if (!Objects.equals(details.get(VmDetailConstants.ACTIVE_CHECKPOINT_ID), checkpointId)) {
|
||||
logger.warn("Checkpoint ID {} does not match active checkpoint for VM {}", checkpointId, vmUuid);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,19 +22,19 @@ import java.time.Instant;
|
|||
import org.apache.cloudstack.veeam.api.dto.Checkpoint;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.cloud.vm.UserVmVO;
|
||||
import com.cloud.utils.NumbersUtil;
|
||||
|
||||
public class UserVmVOToCheckpointConverter {
|
||||
|
||||
public static Checkpoint toCheckpoint(final UserVmVO vm) {
|
||||
if (StringUtils.isEmpty(vm.getActiveCheckpointId())) {
|
||||
public static Checkpoint toCheckpoint(String checkpointId, String createTimeStr) {
|
||||
if (StringUtils.isEmpty(checkpointId)) {
|
||||
return null;
|
||||
}
|
||||
Checkpoint checkpoint = new Checkpoint();
|
||||
checkpoint.setId(vm.getActiveCheckpointId());
|
||||
checkpoint.setName(vm.getActiveCheckpointId());
|
||||
Long createTimeSeconds = vm.getActiveCheckpointCreateTime();
|
||||
if (createTimeSeconds != null) {
|
||||
checkpoint.setId(checkpointId);
|
||||
checkpoint.setName(checkpointId);
|
||||
long createTimeSeconds = createTimeStr != null ? NumbersUtil.parseLong(createTimeStr, 0L) : 0L;
|
||||
if (createTimeSeconds > 0) {
|
||||
checkpoint.setCreationDate(String.valueOf(Instant.ofEpochSecond(createTimeSeconds).toEpochMilli()));
|
||||
} else {
|
||||
checkpoint.setCreationDate(String.valueOf(System.currentTimeMillis()));
|
||||
|
|
|
|||
|
|
@ -78,7 +78,9 @@ import com.cloud.utils.component.ManagerBase;
|
|||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.vm.VMInstanceVO;
|
||||
import com.cloud.vm.VirtualMachine.State;
|
||||
import com.cloud.vm.VmDetailConstants;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
import com.cloud.vm.dao.VMInstanceDetailsDao;
|
||||
|
||||
import static org.apache.cloudstack.backup.BackupManager.BackupFrameworkEnabled;
|
||||
import static org.apache.cloudstack.backup.BackupManager.BackupProviderPlugin;
|
||||
|
|
@ -89,6 +91,9 @@ public class KVMBackupExportServiceImpl extends ManagerBase implements KVMBackup
|
|||
@Inject
|
||||
private VMInstanceDao vmInstanceDao;
|
||||
|
||||
@Inject
|
||||
private VMInstanceDetailsDao vmInstanceDetailsDao;
|
||||
|
||||
@Inject
|
||||
private BackupDao backupDao;
|
||||
|
||||
|
|
@ -164,15 +169,14 @@ public class KVMBackupExportServiceImpl extends ManagerBase implements KVMBackup
|
|||
backup.setDate(new Date());
|
||||
|
||||
String toCheckpointId = "ckp-" + UUID.randomUUID().toString().substring(0, 8);
|
||||
String fromCheckpointId = vm.getActiveCheckpointId();
|
||||
Map<String, String> vmDetails = vmInstanceDetailsDao.listDetailsKeyPairs(vmId);
|
||||
String fromCheckpointId = vmDetails.get(VmDetailConstants.ACTIVE_CHECKPOINT_ID);
|
||||
|
||||
backup.setToCheckpointId(toCheckpointId);
|
||||
backup.setFromCheckpointId(fromCheckpointId);
|
||||
|
||||
Long hostId = vm.getHostId() != null ? vm.getHostId() : vm.getLastHostId();
|
||||
backup.setHostId(hostId);
|
||||
// Will be changed later if incremental was done
|
||||
backup.setType("FULL");
|
||||
|
||||
return backupDao.persist(backup);
|
||||
}
|
||||
|
|
@ -200,11 +204,14 @@ public class KVMBackupExportServiceImpl extends ManagerBase implements KVMBackup
|
|||
long hostId = backup.getHostId();
|
||||
|
||||
Host host = hostDao.findById(hostId);
|
||||
Map<String, String> vmDetails = vmInstanceDetailsDao.listDetailsKeyPairs(vmId);
|
||||
String activeCkpCreateTimeStr = vmDetails.get(VmDetailConstants.ACTIVE_CHECKPOINT_CREATE_TIME);
|
||||
Long fromCheckpointCreateTime = activeCkpCreateTimeStr != null ? NumbersUtil.parseLong(activeCkpCreateTimeStr, 0L) : null;
|
||||
StartBackupCommand startCmd = new StartBackupCommand(
|
||||
vm.getInstanceName(),
|
||||
backup.getToCheckpointId(),
|
||||
backup.getFromCheckpointId(),
|
||||
vm.getActiveCheckpointCreateTime(),
|
||||
fromCheckpointCreateTime,
|
||||
backup.getUuid(),
|
||||
diskPathUuidMap,
|
||||
vm.getState() == State.Stopped
|
||||
|
|
@ -227,10 +234,6 @@ public class KVMBackupExportServiceImpl extends ManagerBase implements KVMBackup
|
|||
|
||||
// Update backup with checkpoint creation time
|
||||
backup.setCheckpointCreateTime(answer.getCheckpointCreateTime());
|
||||
if (Boolean.TRUE.equals(answer.getIncremental())) {
|
||||
// todo: set it in the backend
|
||||
backup.setType("Incremental");
|
||||
}
|
||||
updateBackupState(backup, Backup.Status.ReadyForTransfer);
|
||||
return backup;
|
||||
}
|
||||
|
|
@ -240,6 +243,24 @@ public class KVMBackupExportServiceImpl extends ManagerBase implements KVMBackup
|
|||
backupDao.update(backup.getId(), backup);
|
||||
}
|
||||
|
||||
private void updateVmCheckpoints(Long vmId, BackupVO backup) {
|
||||
Map<String, String> vmDetails = vmInstanceDetailsDao.listDetailsKeyPairs(vmId);
|
||||
String oldCheckpointId = vmDetails.get(VmDetailConstants.ACTIVE_CHECKPOINT_ID);
|
||||
String oldCreateTimeStr = vmDetails.get(VmDetailConstants.ACTIVE_CHECKPOINT_CREATE_TIME);
|
||||
if (oldCheckpointId != null && oldCreateTimeStr != null) {
|
||||
vmInstanceDetailsDao.addDetail(vmId, VmDetailConstants.LAST_CHECKPOINT_ID, oldCheckpointId, false);
|
||||
vmInstanceDetailsDao.addDetail(vmId, VmDetailConstants.LAST_CHECKPOINT_CREATE_TIME, oldCreateTimeStr, false);
|
||||
}
|
||||
String newCheckpointId = backup.getToCheckpointId();
|
||||
Long newCreateTime = backup.getCheckpointCreateTime();
|
||||
if (newCheckpointId != null && newCreateTime != null) {
|
||||
vmInstanceDetailsDao.addDetail(vmId, VmDetailConstants.ACTIVE_CHECKPOINT_ID, backup.getToCheckpointId(), false);
|
||||
vmInstanceDetailsDao.addDetail(vmId, VmDetailConstants.ACTIVE_CHECKPOINT_CREATE_TIME, String.valueOf(newCreateTime), false);
|
||||
} else {
|
||||
logger.error("New checkpoint details are missing for backup {} and vm {}", backup.getId(), vmId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Backup finalizeBackup(FinalizeBackupCmd cmd) {
|
||||
Long vmId = cmd.getVmId();
|
||||
|
|
@ -277,29 +298,18 @@ public class KVMBackupExportServiceImpl extends ManagerBase implements KVMBackup
|
|||
try {
|
||||
answer = (StopBackupAnswer) agentManager.send(backup.getHostId(), stopCmd);
|
||||
} catch (AgentUnavailableException | OperationTimedoutException e) {
|
||||
updateBackupState(backup, Backup.Status.Failed);
|
||||
removeFailedBackup(backup);
|
||||
throw new CloudRuntimeException("Failed to communicate with agent", e);
|
||||
}
|
||||
|
||||
if (!answer.getResult()) {
|
||||
updateBackupState(backup, Backup.Status.Failed);
|
||||
removeFailedBackup(backup);
|
||||
throw new CloudRuntimeException("Failed to stop backup: " + answer.getDetails());
|
||||
}
|
||||
}
|
||||
|
||||
// Update VM checkpoint tracking
|
||||
String oldCheckpointId = vm.getActiveCheckpointId();
|
||||
vm.setActiveCheckpointId(backup.getToCheckpointId());
|
||||
vm.setActiveCheckpointCreateTime(backup.getCheckpointCreateTime());
|
||||
vmInstanceDao.update(vmId, vm);
|
||||
updateVmCheckpoints(vmId, backup);
|
||||
|
||||
// Delete old checkpoint if exists (POC: skip actual libvirt call)
|
||||
if (oldCheckpointId != null) {
|
||||
// todo: In production: send command to delete oldCheckpointId via virsh checkpoint-delete
|
||||
logger.debug("Would delete old checkpoint: {}", oldCheckpointId);
|
||||
}
|
||||
|
||||
// Delete backup session record
|
||||
updateBackupState(backup, Backup.Status.BackedUp);
|
||||
backupDao.remove(backup.getId());
|
||||
|
||||
|
|
@ -322,8 +332,9 @@ public class KVMBackupExportServiceImpl extends ManagerBase implements KVMBackup
|
|||
String socket = backup.getUuid();
|
||||
VMInstanceVO vm = vmInstanceDao.findById(backup.getVmId());
|
||||
if (vm.getState() == State.Stopped) {
|
||||
Map<String, String> vmDetails = vmInstanceDetailsDao.listDetailsKeyPairs(backup.getVmId());
|
||||
String volumePath = getVolumePathForFileBasedBackend(volume);
|
||||
startNBDServer(transferId, direction, backup.getHostId(), volume.getUuid(), volumePath, vm.getActiveCheckpointId());
|
||||
startNBDServer(transferId, direction, backup.getHostId(), volume.getUuid(), volumePath, vmDetails.get(VmDetailConstants.ACTIVE_CHECKPOINT_ID));
|
||||
socket = transferId;
|
||||
}
|
||||
|
||||
|
|
@ -682,31 +693,34 @@ public class KVMBackupExportServiceImpl extends ManagerBase implements KVMBackup
|
|||
return transfers.stream().map(this::toImageTransferResponse).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private CheckpointResponse createCheckpointResponse(String checkpointId, String createTime, boolean isActive) {
|
||||
CheckpointResponse response = new CheckpointResponse();
|
||||
response.setObjectName("checkpoint");
|
||||
response.setId(checkpointId);
|
||||
Long createTimeSeconds = createTime != null ? NumbersUtil.parseLong(createTime, 0L) : 0L;
|
||||
response.setCreated(Date.from(Instant.ofEpochSecond(createTimeSeconds)));
|
||||
response.setIsActive(isActive);
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CheckpointResponse> listVmCheckpoints(ListVmCheckpointsCmd cmd) {
|
||||
Long vmId = cmd.getVmId();
|
||||
|
||||
VMInstanceVO vm = vmInstanceDao.findById(vmId);
|
||||
if (vm == null) {
|
||||
throw new CloudRuntimeException("VM not found: " + vmId);
|
||||
}
|
||||
|
||||
// Return active checkpoint (POC: simplified, no libvirt query)
|
||||
List<CheckpointResponse> responses = new ArrayList<>();
|
||||
if (vm.getActiveCheckpointId() == null) {
|
||||
return responses;
|
||||
|
||||
Map<String, String> details = vmInstanceDetailsDao.listDetailsKeyPairs(vmId);
|
||||
String activeCheckpointId = details.get(VmDetailConstants.ACTIVE_CHECKPOINT_ID);
|
||||
if (activeCheckpointId != null) {
|
||||
responses.add(createCheckpointResponse(activeCheckpointId, details.get(VmDetailConstants.ACTIVE_CHECKPOINT_CREATE_TIME), true));
|
||||
}
|
||||
CheckpointResponse response = new CheckpointResponse();
|
||||
response.setObjectName("checkpoint");
|
||||
response.setId(vm.getActiveCheckpointId());
|
||||
Long createTimeSeconds = vm.getActiveCheckpointCreateTime();
|
||||
if (createTimeSeconds != null) {
|
||||
response.setCreated(Date.from(Instant.ofEpochSecond(createTimeSeconds)));
|
||||
} else {
|
||||
response.setCreated(new Date());
|
||||
String lastCheckpointId = details.get(VmDetailConstants.LAST_CHECKPOINT_ID);
|
||||
if (lastCheckpointId != null) {
|
||||
responses.add(createCheckpointResponse(lastCheckpointId, details.get(VmDetailConstants.LAST_CHECKPOINT_CREATE_TIME), false));
|
||||
}
|
||||
response.setIsActive(true);
|
||||
responses.add(response);
|
||||
return responses;
|
||||
}
|
||||
|
||||
|
|
@ -722,9 +736,9 @@ public class KVMBackupExportServiceImpl extends ManagerBase implements KVMBackup
|
|||
" backup provider. Either set backup.framework.enabled to false or set the Zone level config backup.framework.provider.plugin to \"dummy\".");
|
||||
}
|
||||
|
||||
vm.setActiveCheckpointId(null);
|
||||
vm.setActiveCheckpointCreateTime(null);
|
||||
vmInstanceDao.update(cmd.getVmId(), vm);
|
||||
long vmId = cmd.getVmId();
|
||||
vmInstanceDetailsDao.removeDetail(vmId, VmDetailConstants.ACTIVE_CHECKPOINT_ID);
|
||||
vmInstanceDetailsDao.removeDetail(vmId, VmDetailConstants.ACTIVE_CHECKPOINT_CREATE_TIME);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue