Skip to content

Commit

Permalink
linstor: Support VM-Instance Disk snapshots
Browse files Browse the repository at this point in the history
This adds support 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, snapshot is done
over multiple volumes in the same devicemanager run.
  • Loading branch information
rp- committed Mar 15, 2024
1 parent 40cd088 commit ad8a523
Show file tree
Hide file tree
Showing 3 changed files with 370 additions and 7 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 @@ -1003,8 +1004,8 @@ protected Answer copySnapshot(DataObject srcData, DataObject destData) {
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 +1016,42 @@ 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();

// vmsnapshot don't have our typical snapshot path set, so we have to fix it here
if (!(snapshotObject.getPath().startsWith("/dev/mapper/") ||
snapshotObject.getPath().startsWith("zfs://"))) {
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);
}

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, 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.toString());
}

}
Expand Down
Loading

0 comments on commit ad8a523

Please sign in to comment.