4141import org .apache .commons .lang3 .StringUtils ;
4242import org .libvirt .LibvirtException ;
4343
44- import java .io .File ;
4544import java .io .IOException ;
4645import java .nio .file .Files ;
46+ import java .nio .file .Path ;
4747import java .nio .file .Paths ;
4848import java .util .List ;
4949import java .util .Locale ;
@@ -56,10 +56,25 @@ public class LibvirtRestoreBackupCommandWrapper extends CommandWrapper<RestoreBa
5656 private static final String UMOUNT_COMMAND = "sudo umount %s" ;
5757 private static final String FILE_PATH_PLACEHOLDER = "%s/%s" ;
5858 private static final String ATTACH_QCOW2_DISK_COMMAND = " virsh attach-disk %s %s %s --driver qemu --subdriver qcow2 --cache none" ;
59+ private static final String ATTACH_RAW_DISK_COMMAND = " virsh attach-disk %s %s %s --driver qemu --cache none" ;
5960 private static final String ATTACH_RBD_DISK_XML_COMMAND = " virsh attach-device %s /dev/stdin <<EOF%sEOF" ;
6061 private static final String CURRRENT_DEVICE = "virsh domblklist --domain %s | tail -n 3 | head -n 1 | awk '{print $1}'" ;
6162 private static final String RSYNC_COMMAND = "rsync -az %s %s" ;
6263
64+ private String getVolumeUuidFromPath (String volumePath , PrimaryDataStoreTO volumePool ) {
65+ if (Storage .StoragePoolType .Linstor .equals (volumePool .getPoolType ())) {
66+ Path path = Paths .get (volumePath );
67+ String rscName = path .getParent ().getFileName ().toString ();
68+ if (rscName .startsWith ("cs-" )) {
69+ rscName = rscName .substring (3 );
70+ }
71+ return rscName ;
72+ } else {
73+ int lastIndex = volumePath .lastIndexOf ("/" );
74+ return volumePath .substring (lastIndex + 1 );
75+ }
76+ }
77+
6378 @ Override
6479 public Answer execute (RestoreBackupCommand command , LibvirtComputingResource serverResource ) {
6580 String vmName = command .getVmName ();
@@ -84,9 +99,9 @@ public Answer execute(RestoreBackupCommand command, LibvirtComputingResource ser
8499 PrimaryDataStoreTO volumePool = restoreVolumePools .get (0 );
85100 String volumePath = restoreVolumePaths .get (0 );
86101 String backupFile = backupFiles .get (0 );
87- int lastIndex = volumePath . lastIndexOf ( "/" );
88- newVolumeId = volumePath . substring ( lastIndex + 1 );
89- restoreVolume (storagePoolMgr , backupPath , volumePool , volumePath , diskType , backupFile ,
102+ newVolumeId = getVolumeUuidFromPath ( volumePath , volumePool );
103+ Long size = command . getRestoreVolumeSizes (). get ( 0 );
104+ restoreVolume (storagePoolMgr , backupPath , volumePool , volumePath , diskType , backupFile , size ,
90105 new Pair <>(vmName , command .getVmState ()), mountDirectory , timeout );
91106 } else if (Boolean .TRUE .equals (vmExists )) {
92107 restoreVolumesOfExistingVM (storagePoolMgr , restoreVolumePools , restoreVolumePaths , backedVolumeUUIDs , backupPath , backupFiles , mountDirectory , timeout );
@@ -143,7 +158,7 @@ private void restoreVolumesOfDestroyedVMs(KVMStoragePoolManager storagePoolMgr,
143158 String volumePath = volumePaths .get (i );
144159 String backupFile = backupFiles .get (i );
145160 String bkpPath = getBackupPath (mountDirectory , backupPath , backupFile , diskType );
146- String volumeUuid = volumePath . substring (volumePath . lastIndexOf ( File . separator ) + 1 );
161+ String volumeUuid = getVolumeUuidFromPath (volumePath , volumePool );
147162 diskType = "datadisk" ;
148163 verifyBackupFile (bkpPath , volumeUuid );
149164 if (!replaceVolumeWithBackup (storagePoolMgr , volumePool , volumePath , bkpPath , timeout )) {
@@ -157,14 +172,14 @@ private void restoreVolumesOfDestroyedVMs(KVMStoragePoolManager storagePoolMgr,
157172 }
158173
159174 private void restoreVolume (KVMStoragePoolManager storagePoolMgr , String backupPath , PrimaryDataStoreTO volumePool , String volumePath , String diskType , String backupFile ,
160- Pair <String , VirtualMachine .State > vmNameAndState , String mountDirectory , int timeout ) {
175+ Long size , Pair <String , VirtualMachine .State > vmNameAndState , String mountDirectory , int timeout ) {
161176 String bkpPath ;
162177 String volumeUuid ;
163178 try {
164179 bkpPath = getBackupPath (mountDirectory , backupPath , backupFile , diskType );
165- volumeUuid = volumePath . substring (volumePath . lastIndexOf ( File . separator ) + 1 );
180+ volumeUuid = getVolumeUuidFromPath (volumePath , volumePool );
166181 verifyBackupFile (bkpPath , volumeUuid );
167- if (!replaceVolumeWithBackup (storagePoolMgr , volumePool , volumePath , bkpPath , timeout , true )) {
182+ if (!replaceVolumeWithBackup (storagePoolMgr , volumePool , volumePath , bkpPath , timeout , true , size )) {
168183 throw new CloudRuntimeException (String .format ("Unable to restore contents from the backup volume [%s]." , volumeUuid ));
169184
170185 }
@@ -247,28 +262,38 @@ private boolean checkBackupPathExists(String backupPath) {
247262 }
248263
249264 private boolean replaceVolumeWithBackup (KVMStoragePoolManager storagePoolMgr , PrimaryDataStoreTO volumePool , String volumePath , String backupPath , int timeout ) {
250- return replaceVolumeWithBackup (storagePoolMgr , volumePool , volumePath , backupPath , timeout , false );
265+ return replaceVolumeWithBackup (storagePoolMgr , volumePool , volumePath , backupPath , timeout , false , null );
251266 }
252267
253- private boolean replaceVolumeWithBackup (KVMStoragePoolManager storagePoolMgr , PrimaryDataStoreTO volumePool , String volumePath , String backupPath , int timeout , boolean createTargetVolume ) {
254- if (volumePool .getPoolType () != Storage .StoragePoolType .RBD ) {
255- int exitValue = Script .runSimpleBashScriptForExitValue (String .format (RSYNC_COMMAND , backupPath , volumePath ));
256- return exitValue == 0 ;
268+ private boolean replaceVolumeWithBackup (KVMStoragePoolManager storagePoolMgr , PrimaryDataStoreTO volumePool , String volumePath , String backupPath , int timeout , boolean createTargetVolume , Long size ) {
269+ if (List .of (Storage .StoragePoolType .RBD , Storage .StoragePoolType .Linstor ).contains (volumePool .getPoolType ())) {
270+ return replaceBlockDeviceWithBackup (storagePoolMgr , volumePool , volumePath , backupPath , timeout , createTargetVolume , size );
257271 }
258272
259- return replaceRbdVolumeWithBackup (storagePoolMgr , volumePool , volumePath , backupPath , timeout , createTargetVolume );
273+ int exitValue = Script .runSimpleBashScriptForExitValue (String .format (RSYNC_COMMAND , backupPath , volumePath ));
274+ return exitValue == 0 ;
260275 }
261276
262- private boolean replaceRbdVolumeWithBackup (KVMStoragePoolManager storagePoolMgr , PrimaryDataStoreTO volumePool , String volumePath , String backupPath , int timeout , boolean createTargetVolume ) {
277+ private boolean replaceBlockDeviceWithBackup (KVMStoragePoolManager storagePoolMgr , PrimaryDataStoreTO volumePool , String volumePath , String backupPath , int timeout , boolean createTargetVolume , Long size ) {
263278 KVMStoragePool volumeStoragePool = storagePoolMgr .getStoragePool (volumePool .getPoolType (), volumePool .getUuid ());
264279 QemuImg qemu ;
265280 try {
266281 qemu = new QemuImg (timeout * 1000 , true , false );
267- if (!createTargetVolume ) {
268- KVMPhysicalDisk rdbDisk = volumeStoragePool .getPhysicalDisk (volumePath );
269- logger .debug ("Restoring RBD volume: {}" , rdbDisk .toString ());
282+ String volumeUuid = getVolumeUuidFromPath (volumePath , volumePool );
283+ KVMPhysicalDisk disk = null ;
284+ if (createTargetVolume ) {
285+ if (Storage .StoragePoolType .Linstor .equals (volumePool .getPoolType ())) {
286+ disk = volumeStoragePool .createPhysicalDisk (volumeUuid , QemuImg .PhysicalDiskFormat .RAW , Storage .ProvisioningType .THIN , size , null );
287+ }
288+ } else {
289+ if (Storage .StoragePoolType .Linstor .equals (volumePool .getPoolType ())) {
290+ storagePoolMgr .connectPhysicalDisk (volumePool .getPoolType (), volumePool .getUuid (), volumeUuid , null );
291+ } else {
292+ disk = volumeStoragePool .getPhysicalDisk (getVolumeUuidFromPath (volumePath , volumePool ));
293+ }
270294 qemu .setSkipTargetVolumeCreation (true );
271295 }
296+ logger .debug ("Restoring volume: {}" , disk .toString ());
272297 } catch (LibvirtException ex ) {
273298 throw new CloudRuntimeException ("Failed to create qemu-img command to restore RBD volume with backup" , ex );
274299 }
@@ -277,12 +302,21 @@ private boolean replaceRbdVolumeWithBackup(KVMStoragePoolManager storagePoolMgr,
277302 QemuImgFile destVolumeFile = null ;
278303 try {
279304 srcBackupFile = new QemuImgFile (backupPath , QemuImg .PhysicalDiskFormat .QCOW2 );
280- String rbdDestVolumeFile = KVMPhysicalDisk .RBDStringBuilder (volumeStoragePool , volumePath );
281- destVolumeFile = new QemuImgFile (rbdDestVolumeFile , QemuImg .PhysicalDiskFormat .RAW );
282-
283- logger .debug ("Starting convert backup {} to RBD volume {}" , backupPath , volumePath );
305+ String destVolume ;
306+ switch (volumePool .getPoolType ()) {
307+ case Linstor :
308+ destVolume = volumePath ;
309+ break ;
310+ case RBD :
311+ destVolume = KVMPhysicalDisk .RBDStringBuilder (volumeStoragePool , volumePath );
312+ break ;
313+ default :
314+ throw new CloudRuntimeException (String .format ("Unsupported storage pool type [%s] for block device restore with backup." , volumePool .getPoolType ()));
315+ }
316+ destVolumeFile = new QemuImgFile (destVolume , QemuImg .PhysicalDiskFormat .RAW );
317+ logger .debug ("Starting convert backup {} to volume {}" , backupPath , volumePath );
284318 qemu .convert (srcBackupFile , destVolumeFile );
285- logger .debug ("Successfully converted backup {} to RBD volume {}" , backupPath , volumePath );
319+ logger .debug ("Successfully converted backup {} to volume {}" , backupPath , volumePath );
286320 } catch (QemuImgException | LibvirtException e ) {
287321 String srcFilename = srcBackupFile != null ? srcBackupFile .getFileName () : null ;
288322 String destFilename = destVolumeFile != null ? destVolumeFile .getFileName () : null ;
@@ -296,12 +330,14 @@ private boolean replaceRbdVolumeWithBackup(KVMStoragePoolManager storagePoolMgr,
296330 private boolean attachVolumeToVm (KVMStoragePoolManager storagePoolMgr , String vmName , PrimaryDataStoreTO volumePool , String volumePath ) {
297331 String deviceToAttachDiskTo = getDeviceToAttachDisk (vmName );
298332 int exitValue ;
299- if (volumePool .getPoolType () != Storage .StoragePoolType .RBD ) {
300- exitValue = Script .runSimpleBashScriptForExitValue (String .format (ATTACH_QCOW2_DISK_COMMAND , vmName , volumePath , deviceToAttachDiskTo ));
301- } else {
333+ if (volumePool .getPoolType () == Storage .StoragePoolType .RBD ) {
302334 String xmlForRbdDisk = getXmlForRbdDisk (storagePoolMgr , volumePool , volumePath , deviceToAttachDiskTo );
303335 logger .debug ("RBD disk xml to attach: {}" , xmlForRbdDisk );
304336 exitValue = Script .runSimpleBashScriptForExitValue (String .format (ATTACH_RBD_DISK_XML_COMMAND , vmName , xmlForRbdDisk ));
337+ } else if (volumePool .getPoolType () == Storage .StoragePoolType .Linstor ) {
338+ exitValue = Script .runSimpleBashScriptForExitValue (String .format (ATTACH_RAW_DISK_COMMAND , vmName , volumePath , deviceToAttachDiskTo ));
339+ } else {
340+ exitValue = Script .runSimpleBashScriptForExitValue (String .format (ATTACH_QCOW2_DISK_COMMAND , vmName , volumePath , deviceToAttachDiskTo ));
305341 }
306342 return exitValue == 0 ;
307343 }
0 commit comments