Skip to content

Commit b75d6a8

Browse files
rp-dhslove
authored andcommitted
linstor: Support VM-Instance Disk snapshots (apache#8796)
* linstor: update to java-linstor 0.5.1 * linstor: Support VM-Instance Disk snapshots 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.
1 parent cf8c768 commit b75d6a8

File tree

5 files changed

+421
-17
lines changed

5 files changed

+421
-17
lines changed

plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/driver/LinstorPrimaryDataStoreDriverImpl.java

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ private void deleteSnapshot(@Nonnull DataStore dataStore, @Nonnull String rscDef
232232

233233
try
234234
{
235-
ApiCallRcList answers = linstorApi.resourceSnapshotDelete(rscDefName, snapshotName);
235+
ApiCallRcList answers = linstorApi.resourceSnapshotDelete(rscDefName, snapshotName, Collections.emptyList());
236236
if (answers.hasError())
237237
{
238238
for (ApiCallRc answer : answers)
@@ -1004,25 +1004,29 @@ private Answer copyVolume(DataObject srcData, DataObject dstData) {
10041004
* @param api Linstor Developer api object
10051005
* @param pool StoragePool this resource resides on
10061006
* @param rscName rscName of the snapshotted resource
1007-
* @param snapshotInfo snapshot info of the snapshot
1007+
* @param snapshotName Name of the snapshot to copy from
1008+
* @param snapshotObject snapshot object of the origCmd, so the path can be modified
10081009
* @param origCmd original LinstorBackupSnapshotCommand that needs to have a patched path
10091010
* @return answer from agent operation
10101011
* @throws ApiException if any Linstor api operation fails
10111012
*/
10121013
private Answer copyFromTemporaryResource(
1013-
DevelopersApi api, StoragePoolVO pool, String rscName, SnapshotInfo snapshotInfo, CopyCommand origCmd)
1014+
DevelopersApi api,
1015+
StoragePoolVO pool,
1016+
String rscName,
1017+
String snapshotName,
1018+
SnapshotObject snapshotObject,
1019+
CopyCommand origCmd)
10141020
throws ApiException {
10151021
Answer answer;
10161022
String restoreName = rscName + "-rst";
1017-
String snapshotName = LinstorUtil.RSC_PREFIX + snapshotInfo.getUuid();
10181023
String devName = restoreResourceFromSnapshot(api, pool, rscName, snapshotName, restoreName);
10191024

10201025
Optional<RemoteHostEndPoint> optEPAny = getLinstorEP(api, restoreName);
10211026
if (optEPAny.isPresent()) {
10221027
// patch the src device path to the temporary linstor resource
1023-
SnapshotObjectTO soTO = (SnapshotObjectTO)snapshotInfo.getTO();
1024-
soTO.setPath(devName);
1025-
origCmd.setSrcTO(soTO);
1028+
snapshotObject.setPath(devName);
1029+
origCmd.setSrcTO(snapshotObject.getTO());
10261030
answer = optEPAny.get().sendMessage(origCmd);
10271031
} else{
10281032
answer = new Answer(origCmd, false, "Unable to get matching Linstor endpoint.");
@@ -1032,13 +1036,36 @@ private Answer copyFromTemporaryResource(
10321036
return answer;
10331037
}
10341038

1039+
/**
1040+
* vmsnapshots don't have our typical snapshot path set
1041+
* instead the path is the internal snapshot name e.g.: {vm}_VS_{datestr}
1042+
* we have to find out and modify the path here before
1043+
* @return the original snapshotObject.getPath()
1044+
*/
1045+
private String setCorrectSnapshotPath(DevelopersApi api, String rscName, SnapshotObject snapshotObject)
1046+
throws ApiException {
1047+
String originalPath = LinstorUtil.RSC_PREFIX + snapshotObject.getUuid();
1048+
if (!(snapshotObject.getPath().startsWith("/dev/mapper/") ||
1049+
snapshotObject.getPath().startsWith("zfs://"))) {
1050+
originalPath = snapshotObject.getPath();
1051+
com.linbit.linstor.api.model.StoragePool linStoragePool =
1052+
LinstorUtil.getDiskfulStoragePool(api, rscName);
1053+
if (linStoragePool == null) {
1054+
throw new CloudRuntimeException("Linstor: Unable to find storage pool for resource " + rscName);
1055+
}
1056+
final String path = LinstorUtil.getSnapshotPath(linStoragePool, rscName, snapshotObject.getPath());
1057+
snapshotObject.setPath(path);
1058+
}
1059+
return originalPath;
1060+
}
1061+
10351062
protected Answer copySnapshot(DataObject srcData, DataObject destData) {
10361063
String value = _configDao.getValue(Config.BackupSnapshotWait.toString());
10371064
int _backupsnapshotwait = NumbersUtil.parseInt(
10381065
value, Integer.parseInt(Config.BackupSnapshotWait.getDefaultValue()));
10391066

1040-
SnapshotInfo snapshotInfo = (SnapshotInfo)srcData;
1041-
Boolean snapshotFullBackup = snapshotInfo.getFullBackup();
1067+
SnapshotObject snapshotObject = (SnapshotObject)srcData;
1068+
Boolean snapshotFullBackup = snapshotObject.getFullBackup();
10421069
final StoragePoolVO pool = _storagePoolDao.findById(srcData.getDataStore().getId());
10431070
final DevelopersApi api = LinstorUtil.getLinstorAPI(pool.getHostAddress());
10441071
boolean fullSnapshot = true;
@@ -1049,29 +1076,31 @@ protected Answer copySnapshot(DataObject srcData, DataObject destData) {
10491076
options.put("fullSnapshot", fullSnapshot + "");
10501077
options.put(SnapshotInfo.BackupSnapshotAfterTakingSnapshot.key(),
10511078
String.valueOf(SnapshotInfo.BackupSnapshotAfterTakingSnapshot.value()));
1052-
options.put("volumeSize", snapshotInfo.getBaseVolume().getSize() + "");
1079+
options.put("volumeSize", snapshotObject.getBaseVolume().getSize() + "");
10531080

10541081
try {
1082+
final String rscName = LinstorUtil.RSC_PREFIX + snapshotObject.getBaseVolume().getUuid();
1083+
String snapshotName = setCorrectSnapshotPath(api, rscName, snapshotObject);
1084+
10551085
CopyCommand cmd = new LinstorBackupSnapshotCommand(
1056-
srcData.getTO(),
1086+
snapshotObject.getTO(),
10571087
destData.getTO(),
10581088
_backupsnapshotwait,
10591089
VirtualMachineManager.ExecuteInSequence.value());
10601090
cmd.setOptions(options);
10611091

1062-
String rscName = LinstorUtil.RSC_PREFIX + snapshotInfo.getBaseVolume().getUuid();
10631092
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(api, rscName);
10641093
Answer answer;
10651094
if (optEP.isPresent()) {
10661095
answer = optEP.get().sendMessage(cmd);
10671096
} else {
10681097
logger.debug("No diskfull endpoint found to copy image, creating diskless endpoint");
1069-
answer = copyFromTemporaryResource(api, pool, rscName, snapshotInfo, cmd);
1098+
answer = copyFromTemporaryResource(api, pool, rscName, snapshotName, snapshotObject, cmd);
10701099
}
10711100
return answer;
10721101
} catch (Exception e) {
10731102
logger.debug("copy snapshot failed: ", e);
1074-
throw new CloudRuntimeException(e.toString());
1103+
throw new CloudRuntimeException("Copy snapshot failed, please cleanup snapshot manually: " + e);
10751104
}
10761105

10771106
}

plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/util/LinstorUtil.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ public static List<String> getLinstorNodeNames(@Nonnull DevelopersApi api) throw
113113
Collections.singletonList(storagePoolName),
114114
Collections.emptyList(),
115115
null,
116-
null
116+
null,
117+
true
117118
);
118119
return sps != null ? sps : Collections.emptyList();
119120
}
@@ -167,7 +168,8 @@ public static List<StoragePool> getRscGroupStoragePools(DevelopersApi api, Strin
167168
rscGrps.get(0).getSelectFilter().getStoragePoolList(),
168169
null,
169170
null,
170-
null
171+
null,
172+
true
171173
);
172174
}
173175

0 commit comments

Comments
 (0)