@@ -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 ) {
0 commit comments