Skip to content

Commit

Permalink
linstor: Support VM-Instance Disk snapshots
Browse files Browse the repository at this point in the history
This adds VM-Instance disk snapshot support for
Linstor primary storage. Instance snapshots are stored on
the used Linstor storage pool backend and can be converted
into regular volume snapshots and also reverted.

Instance VM snapshots are not fully atomic but with the
create multi snapshot feature as good as it gets.
Snapshots are done over multiple volumes in the same devicemanager run.
  • Loading branch information
rp- committed Mar 29, 2024
1 parent 2984690 commit 151fde5
Show file tree
Hide file tree
Showing 3 changed files with 406 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.datastore.util.LinstorConfigurationManager;
import org.apache.cloudstack.storage.datastore.util.LinstorUtil;
import org.apache.cloudstack.storage.snapshot.SnapshotObject;
import org.apache.cloudstack.storage.to.SnapshotObjectTO;
import org.apache.cloudstack.storage.volume.VolumeObject;
import org.apache.log4j.Logger;
Expand Down Expand Up @@ -970,25 +971,29 @@ private Answer copyTemplate(DataObject srcData, DataObject dstData) {
* @param api Linstor Developer api object
* @param pool StoragePool this resource resides on
* @param rscName rscName of the snapshotted resource
* @param snapshotInfo snapshot info of the snapshot
* @param snapshotName Name of the snapshot to copy from
* @param snapshotObject snapshot object of the origCmd, so the path can be modified
* @param origCmd original LinstorBackupSnapshotCommand that needs to have a patched path
* @return answer from agent operation
* @throws ApiException if any Linstor api operation fails
*/
private Answer copyFromTemporaryResource(
DevelopersApi api, StoragePoolVO pool, String rscName, SnapshotInfo snapshotInfo, CopyCommand origCmd)
DevelopersApi api,
StoragePoolVO pool,
String rscName,
String snapshotName,
SnapshotObject snapshotObject,
CopyCommand origCmd)
throws ApiException {
Answer answer;
String restoreName = rscName + "-rst";
String snapshotName = LinstorUtil.RSC_PREFIX + snapshotInfo.getUuid();
String devName = restoreResourceFromSnapshot(api, pool, rscName, snapshotName, restoreName);

Optional<RemoteHostEndPoint> optEPAny = getLinstorEP(api, restoreName);
if (optEPAny.isPresent()) {
// patch the src device path to the temporary linstor resource
SnapshotObjectTO soTO = (SnapshotObjectTO)snapshotInfo.getTO();
soTO.setPath(devName);
origCmd.setSrcTO(soTO);
snapshotObject.setPath(devName);
origCmd.setSrcTO(snapshotObject.getTO());
answer = optEPAny.get().sendMessage(origCmd);
} else{
answer = new Answer(origCmd, false, "Unable to get matching Linstor endpoint.");
Expand All @@ -998,13 +1003,36 @@ private Answer copyFromTemporaryResource(
return answer;
}

/**
* vmsnapshots don't have our typical snapshot path set
* instead the path is the internal snapshot name e.g.: {vm}_VS_{datestr}
* we have to find out and modify the path here before
* @return the original snapshotObject.getPath()
*/
private String setCorrectSnapshotPath(DevelopersApi api, String rscName, SnapshotObject snapshotObject)
throws ApiException {
String originalPath = LinstorUtil.RSC_PREFIX + snapshotObject.getUuid();
if (!(snapshotObject.getPath().startsWith("/dev/mapper/") ||
snapshotObject.getPath().startsWith("zfs://"))) {
originalPath = snapshotObject.getPath();
com.linbit.linstor.api.model.StoragePool linStoragePool =
LinstorUtil.getDiskfulStoragePool(api, rscName);
if (linStoragePool == null) {
throw new CloudRuntimeException("Linstor: Unable to find storage pool for resource " + rscName);
}
final String path = LinstorUtil.getSnapshotPath(linStoragePool, rscName, snapshotObject.getPath());
snapshotObject.setPath(path);
}
return originalPath;
}

protected Answer copySnapshot(DataObject srcData, DataObject destData) {
String value = _configDao.getValue(Config.BackupSnapshotWait.toString());
int _backupsnapshotwait = NumbersUtil.parseInt(
value, Integer.parseInt(Config.BackupSnapshotWait.getDefaultValue()));

SnapshotInfo snapshotInfo = (SnapshotInfo)srcData;
Boolean snapshotFullBackup = snapshotInfo.getFullBackup();
SnapshotObject snapshotObject = (SnapshotObject)srcData;
Boolean snapshotFullBackup = snapshotObject.getFullBackup();
final StoragePoolVO pool = _storagePoolDao.findById(srcData.getDataStore().getId());
final DevelopersApi api = LinstorUtil.getLinstorAPI(pool.getHostAddress());
boolean fullSnapshot = true;
Expand All @@ -1015,29 +1043,31 @@ protected Answer copySnapshot(DataObject srcData, DataObject destData) {
options.put("fullSnapshot", fullSnapshot + "");
options.put(SnapshotInfo.BackupSnapshotAfterTakingSnapshot.key(),
String.valueOf(SnapshotInfo.BackupSnapshotAfterTakingSnapshot.value()));
options.put("volumeSize", snapshotInfo.getBaseVolume().getSize() + "");
options.put("volumeSize", snapshotObject.getBaseVolume().getSize() + "");

try {
final String rscName = LinstorUtil.RSC_PREFIX + snapshotObject.getBaseVolume().getUuid();
String snapshotName = setCorrectSnapshotPath(api, rscName, snapshotObject);

CopyCommand cmd = new LinstorBackupSnapshotCommand(
srcData.getTO(),
snapshotObject.getTO(),
destData.getTO(),
_backupsnapshotwait,
VirtualMachineManager.ExecuteInSequence.value());
cmd.setOptions(options);

String rscName = LinstorUtil.RSC_PREFIX + snapshotInfo.getBaseVolume().getUuid();
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(api, rscName);
Answer answer;
if (optEP.isPresent()) {
answer = optEP.get().sendMessage(cmd);
} else {
s_logger.debug("No diskfull endpoint found to copy image, creating diskless endpoint");
answer = copyFromTemporaryResource(api, pool, rscName, snapshotInfo, cmd);
answer = copyFromTemporaryResource(api, pool, rscName, snapshotName, snapshotObject, cmd);
}
return answer;
} catch (Exception e) {
s_logger.debug("copy snapshot failed: ", e);
throw new CloudRuntimeException(e.toString());
throw new CloudRuntimeException("Copy snapshot failed, please cleanup snapshot manually: " + e);
}

}
Expand Down
Loading

0 comments on commit 151fde5

Please sign in to comment.