Skip to content

Commit 22d0177

Browse files
Merge branch 'main' into 4.19-update-vpctier-offering-conserve-mode
2 parents c2d81af + a15b706 commit 22d0177

2 files changed

Lines changed: 81 additions & 10 deletions

File tree

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

Lines changed: 79 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,16 @@ private String cloneResource(long csCloneId, VolumeInfo volumeInfo, StoragePoolV
527527
}
528528
}
529529

530+
private ResourceDefinitionCreate createResourceDefinitionCreate(String rscName, String rscGrpName)
531+
throws ApiException {
532+
ResourceDefinitionCreate rdCreate = new ResourceDefinitionCreate();
533+
ResourceDefinition rd = new ResourceDefinition();
534+
rd.setName(rscName);
535+
rd.setResourceGroupName(rscGrpName);
536+
rdCreate.setResourceDefinition(rd);
537+
return rdCreate;
538+
}
539+
530540
private String createResourceFromSnapshot(long csSnapshotId, String rscName, StoragePoolVO storagePoolVO) {
531541
final String rscGrp = getRscGrp(storagePoolVO);
532542
final DevelopersApi linstorApi = LinstorUtil.getLinstorAPI(storagePoolVO.getHostAddress());
@@ -539,11 +549,7 @@ private String createResourceFromSnapshot(long csSnapshotId, String rscName, Sto
539549
try
540550
{
541551
s_logger.debug("Create new resource definition: " + rscName);
542-
ResourceDefinitionCreate rdCreate = new ResourceDefinitionCreate();
543-
ResourceDefinition rd = new ResourceDefinition();
544-
rd.setName(rscName);
545-
rd.setResourceGroupName(rscGrp);
546-
rdCreate.setResourceDefinition(rd);
552+
ResourceDefinitionCreate rdCreate = createResourceDefinitionCreate(rscName, rscGrp);
547553
ApiCallRcList answers = linstorApi.resourceDefinitionCreate(rdCreate);
548554
checkLinstorAnswersThrow(answers);
549555

@@ -712,6 +718,10 @@ private String revertSnapshotFromImageStore(
712718
VirtualMachineManager.ExecuteInSequence.value());
713719

714720
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(linstorApi, rscName);
721+
if (optEP.isEmpty()) {
722+
optEP = getLinstorEP(linstorApi, rscName);
723+
}
724+
715725
if (optEP.isPresent()) {
716726
Answer answer = optEP.get().sendMessage(cmd);
717727
if (!answer.getResult()) {
@@ -840,6 +850,14 @@ public void copyAsync(DataObject srcData, DataObject dstData, AsyncCompletionCal
840850
callback.complete(res);
841851
}
842852

853+
/**
854+
* Tries to get a Linstor cloudstack end point, that is at least diskless.
855+
*
856+
* @param api Linstor java api object
857+
* @param rscName resource name to make available on node
858+
* @return Optional RemoteHostEndPoint if one could get found.
859+
* @throws ApiException
860+
*/
843861
private Optional<RemoteHostEndPoint> getLinstorEP(DevelopersApi api, String rscName) throws ApiException {
844862
List<String> linstorNodeNames = LinstorUtil.getLinstorNodeNames(api);
845863
Collections.shuffle(linstorNodeNames); // do not always pick the first linstor node
@@ -892,6 +910,25 @@ private Optional<RemoteHostEndPoint> getDiskfullEP(DevelopersApi api, String rsc
892910
return Optional.empty();
893911
}
894912

913+
private String restoreResourceFromSnapshot(
914+
DevelopersApi api,
915+
StoragePoolVO storagePoolVO,
916+
String rscName,
917+
String snapshotName,
918+
String restoredName) throws ApiException {
919+
final String rscGrp = getRscGrp(storagePoolVO);
920+
ResourceDefinitionCreate rdc = createResourceDefinitionCreate(restoredName, rscGrp);
921+
api.resourceDefinitionCreate(rdc);
922+
923+
SnapshotRestore sr = new SnapshotRestore();
924+
sr.toResource(restoredName);
925+
api.resourceSnapshotsRestoreVolumeDefinition(rscName, snapshotName, sr);
926+
927+
api.resourceSnapshotRestore(rscName, snapshotName, sr);
928+
929+
return getDeviceName(api, restoredName);
930+
}
931+
895932
private Answer copyTemplate(DataObject srcData, DataObject dstData) {
896933
TemplateInfo tInfo = (TemplateInfo) dstData;
897934
final StoragePoolVO pool = _storagePoolDao.findById(dstData.getDataStore().getId());
@@ -929,6 +966,39 @@ private Answer copyTemplate(DataObject srcData, DataObject dstData) {
929966
return answer;
930967
}
931968

969+
/**
970+
* Create a temporary resource from the snapshot to backup, so we can copy the data on a diskless agent
971+
* @param api Linstor Developer api object
972+
* @param pool StoragePool this resource resides on
973+
* @param rscName rscName of the snapshotted resource
974+
* @param snapshotInfo snapshot info of the snapshot
975+
* @param origCmd original LinstorBackupSnapshotCommand that needs to have a patched path
976+
* @return answer from agent operation
977+
* @throws ApiException if any Linstor api operation fails
978+
*/
979+
private Answer copyFromTemporaryResource(
980+
DevelopersApi api, StoragePoolVO pool, String rscName, SnapshotInfo snapshotInfo, CopyCommand origCmd)
981+
throws ApiException {
982+
Answer answer;
983+
String restoreName = rscName + "-rst";
984+
String snapshotName = LinstorUtil.RSC_PREFIX + snapshotInfo.getUuid();
985+
String devName = restoreResourceFromSnapshot(api, pool, rscName, snapshotName, restoreName);
986+
987+
Optional<RemoteHostEndPoint> optEPAny = getLinstorEP(api, restoreName);
988+
if (optEPAny.isPresent()) {
989+
// patch the src device path to the temporary linstor resource
990+
SnapshotObjectTO soTO = (SnapshotObjectTO)snapshotInfo.getTO();
991+
soTO.setPath(devName);
992+
origCmd.setSrcTO(soTO);
993+
answer = optEPAny.get().sendMessage(origCmd);
994+
} else{
995+
answer = new Answer(origCmd, false, "Unable to get matching Linstor endpoint.");
996+
}
997+
// delete the temporary resource, noop if already gone
998+
api.resourceDefinitionDelete(restoreName);
999+
return answer;
1000+
}
1001+
9321002
protected Answer copySnapshot(DataObject srcData, DataObject destData) {
9331003
String value = _configDao.getValue(Config.BackupSnapshotWait.toString());
9341004
int _backupsnapshotwait = NumbersUtil.parseInt(
@@ -956,13 +1026,14 @@ protected Answer copySnapshot(DataObject srcData, DataObject destData) {
9561026
VirtualMachineManager.ExecuteInSequence.value());
9571027
cmd.setOptions(options);
9581028

959-
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(
960-
api, LinstorUtil.RSC_PREFIX + snapshotInfo.getBaseVolume().getUuid());
1029+
String rscName = LinstorUtil.RSC_PREFIX + snapshotInfo.getBaseVolume().getUuid();
1030+
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(api, rscName);
9611031
Answer answer;
9621032
if (optEP.isPresent()) {
9631033
answer = optEP.get().sendMessage(cmd);
9641034
} else {
965-
answer = new Answer(cmd, false, "Unable to get matching Linstor endpoint.");
1035+
s_logger.debug("No diskfull endpoint found to copy image, creating diskless endpoint");
1036+
answer = copyFromTemporaryResource(api, pool, rscName, snapshotInfo, cmd);
9661037
}
9671038
return answer;
9681039
} catch (Exception e) {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121

2222
public class LinstorConfigurationManager implements Configurable
2323
{
24-
public static final ConfigKey<Boolean> BackupSnapshots = new ConfigKey<>(Boolean.class, "lin.backup.snapshots", "Advanced", "false",
25-
"Backup Linstor primary storage snapshots to secondary storage (deleting ps snapshot), only works on hyperconverged setups.", true, ConfigKey.Scope.Global, null);
24+
public static final ConfigKey<Boolean> BackupSnapshots = new ConfigKey<>(Boolean.class, "lin.backup.snapshots", "Advanced", "true",
25+
"Backup Linstor primary storage snapshots to secondary storage (deleting ps snapshot)", true, ConfigKey.Scope.Global, null);
2626

2727
public static final ConfigKey<?>[] CONFIG_KEYS = new ConfigKey<?>[] { BackupSnapshots };
2828

0 commit comments

Comments
 (0)