Skip to content

Commit 2c0473d

Browse files
Support restore from NAS backup to Ceph storage pool(s)
1 parent 0108ffd commit 2c0473d

File tree

5 files changed

+179
-37
lines changed

5 files changed

+179
-37
lines changed

api/src/main/java/org/apache/cloudstack/backup/BackupManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public interface BackupManager extends BackupService, Configurable, PluggableSer
5555
ConfigKey<String> BackupProviderPlugin = new ConfigKey<>("Advanced", String.class,
5656
"backup.framework.provider.plugin",
5757
"dummy",
58-
"The backup and recovery provider plugin.", true, ConfigKey.Scope.Zone, BackupFrameworkEnabled.key());
58+
"The backup and recovery provider plugin. Valid plugin values: dummy, veeam, networker and nas", true, ConfigKey.Scope.Zone, BackupFrameworkEnabled.key());
5959

6060
ConfigKey<Long> BackupSyncPollingInterval = new ConfigKey<>("Advanced", Long.class,
6161
"backup.framework.sync.interval",

core/src/main/java/org/apache/cloudstack/backup/RestoreBackupCommand.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.cloud.agent.api.Command;
2323
import com.cloud.agent.api.LogLevel;
2424
import com.cloud.vm.VirtualMachine;
25+
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
2526

2627
import java.util.List;
2728

@@ -31,6 +32,7 @@ public class RestoreBackupCommand extends Command {
3132
private String backupRepoType;
3233
private String backupRepoAddress;
3334
private List<String> backupVolumesUUIDs;
35+
private List<PrimaryDataStoreTO> restoreVolumePools;
3436
private List<String> restoreVolumePaths;
3537
private String diskType;
3638
private Boolean vmExists;
@@ -73,6 +75,14 @@ public void setBackupRepoAddress(String backupRepoAddress) {
7375
this.backupRepoAddress = backupRepoAddress;
7476
}
7577

78+
public List<PrimaryDataStoreTO> getRestoreVolumePools() {
79+
return restoreVolumePools;
80+
}
81+
82+
public void setRestoreVolumePools(List<PrimaryDataStoreTO> restoreVolumePools) {
83+
this.restoreVolumePools = restoreVolumePools;
84+
}
85+
7686
public List<String> getRestoreVolumePaths() {
7787
return restoreVolumePaths;
7888
}

plugins/backup/nas/src/main/java/org/apache/cloudstack/backup/NASBackupProvider.java

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.cloud.hypervisor.Hypervisor;
2727
import com.cloud.offering.DiskOffering;
2828
import com.cloud.resource.ResourceManager;
29+
import com.cloud.storage.DataStoreRole;
2930
import com.cloud.storage.ScopeType;
3031
import com.cloud.storage.Storage;
3132
import com.cloud.storage.StoragePoolHostVO;
@@ -49,10 +50,13 @@
4950

5051
import org.apache.cloudstack.backup.dao.BackupDao;
5152
import org.apache.cloudstack.backup.dao.BackupRepositoryDao;
53+
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
54+
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
5255
import org.apache.cloudstack.framework.config.ConfigKey;
5356
import org.apache.cloudstack.framework.config.Configurable;
5457
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
5558
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
59+
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
5660
import org.apache.logging.log4j.Logger;
5761
import org.apache.logging.log4j.LogManager;
5862

@@ -97,6 +101,9 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
97101
@Inject
98102
private PrimaryDataStoreDao primaryDataStoreDao;
99103

104+
@Inject
105+
DataStoreManager dataStoreMgr;
106+
100107
@Inject
101108
private AgentManager agentManager;
102109

@@ -179,7 +186,8 @@ public Pair<Boolean, Backup> takeBackup(final VirtualMachine vm, Boolean quiesce
179186
if (VirtualMachine.State.Stopped.equals(vm.getState())) {
180187
List<VolumeVO> vmVolumes = volumeDao.findByInstance(vm.getId());
181188
vmVolumes.sort(Comparator.comparing(Volume::getDeviceId));
182-
List<String> volumePaths = getVolumePaths(vmVolumes);
189+
Pair<List<PrimaryDataStoreTO>, List<String>> volumePoolsAndPaths = getVolumePoolsAndPaths(vmVolumes);
190+
List<String> volumePaths = volumePoolsAndPaths.second();
183191
command.setVolumePaths(volumePaths);
184192
}
185193

@@ -279,7 +287,9 @@ private boolean restoreVMBackup(VirtualMachine vm, Backup backup) {
279287
restoreCommand.setMountOptions(backupRepository.getMountOptions());
280288
restoreCommand.setVmName(vm.getName());
281289
restoreCommand.setBackupVolumesUUIDs(backedVolumesUUIDs);
282-
restoreCommand.setRestoreVolumePaths(getVolumePaths(restoreVolumes));
290+
Pair<List<PrimaryDataStoreTO>, List<String>> volumePoolsAndPaths = getVolumePoolsAndPaths(restoreVolumes);
291+
restoreCommand.setRestoreVolumePools(volumePoolsAndPaths.first());
292+
restoreCommand.setRestoreVolumePaths(volumePoolsAndPaths.second());
283293
restoreCommand.setVmExists(vm.getRemoved() == null);
284294
restoreCommand.setVmState(vm.getState());
285295

@@ -294,32 +304,42 @@ private boolean restoreVMBackup(VirtualMachine vm, Backup backup) {
294304
return answer.getResult();
295305
}
296306

297-
private List<String> getVolumePaths(List<VolumeVO> volumes) {
307+
private Pair<List<PrimaryDataStoreTO>, List<String>> getVolumePoolsAndPaths(List<VolumeVO> volumes) {
308+
List<PrimaryDataStoreTO> volumePools = new ArrayList<>();
298309
List<String> volumePaths = new ArrayList<>();
299310
for (VolumeVO volume : volumes) {
300311
StoragePoolVO storagePool = primaryDataStoreDao.findById(volume.getPoolId());
301312
if (Objects.isNull(storagePool)) {
302313
throw new CloudRuntimeException("Unable to find storage pool associated to the volume");
303314
}
304-
String volumePathPrefix;
305-
if (ScopeType.HOST.equals(storagePool.getScope())) {
306-
volumePathPrefix = storagePool.getPath();
307-
} else if (Storage.StoragePoolType.SharedMountPoint.equals(storagePool.getPoolType())) {
308-
volumePathPrefix = storagePool.getPath();
309-
} else {
310-
volumePathPrefix = String.format("/mnt/%s", storagePool.getUuid());
311-
}
315+
String volumePathPrefix = getVolumePathPrefix(storagePool);
316+
DataStore dataStore = dataStoreMgr.getDataStore(storagePool.getId(), DataStoreRole.Primary);
317+
volumePools.add(dataStore != null ? (PrimaryDataStoreTO)dataStore.getTO() : null);
312318
volumePaths.add(String.format("%s/%s", volumePathPrefix, volume.getPath()));
313319
}
314-
return volumePaths;
320+
return new Pair<>(volumePools, volumePaths);
321+
}
322+
323+
private String getVolumePathPrefix(StoragePoolVO storagePool) {
324+
String volumePathPrefix;
325+
if (ScopeType.HOST.equals(storagePool.getScope()) ||
326+
Storage.StoragePoolType.SharedMountPoint.equals(storagePool.getPoolType()) ||
327+
Storage.StoragePoolType.RBD.equals(storagePool.getPoolType())) {
328+
volumePathPrefix = storagePool.getPath();
329+
} else {
330+
// Should be Storage.StoragePoolType.NetworkFilesystem
331+
volumePathPrefix = String.format("/mnt/%s", storagePool.getUuid());
332+
}
333+
return volumePathPrefix;
315334
}
316335

317336
@Override
318337
public Pair<Boolean, String> restoreBackedUpVolume(Backup backup, Backup.VolumeInfo backupVolumeInfo, String hostIp, String dataStoreUuid, Pair<String, VirtualMachine.State> vmNameAndState) {
319338
final VolumeVO volume = volumeDao.findByUuid(backupVolumeInfo.getUuid());
320339
final DiskOffering diskOffering = diskOfferingDao.findByUuid(backupVolumeInfo.getDiskOfferingId());
321-
final StoragePoolHostVO dataStore = storagePoolHostDao.findByUuid(dataStoreUuid);
340+
final StoragePoolVO pool = primaryDataStoreDao.findByUuid(dataStoreUuid);
322341
final HostVO hostVO = hostDao.findByIp(hostIp);
342+
final StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(pool.getId(), hostVO.getId());
323343

324344
LOG.debug("Restoring vm volume {} from backup {} on the NAS Backup Provider", backupVolumeInfo, backup);
325345
BackupRepository backupRepository = getBackupRepository(backup);
@@ -335,10 +355,14 @@ public Pair<Boolean, String> restoreBackedUpVolume(Backup backup, Backup.VolumeI
335355
restoredVolume.setUuid(volumeUUID);
336356
restoredVolume.setRemoved(null);
337357
restoredVolume.setDisplayVolume(true);
338-
restoredVolume.setPoolId(dataStore.getPoolId());
358+
restoredVolume.setPoolId(pool.getId());
359+
restoredVolume.setPoolType(pool.getPoolType());
339360
restoredVolume.setPath(restoredVolume.getUuid());
340361
restoredVolume.setState(Volume.State.Copying);
341362
restoredVolume.setFormat(Storage.ImageFormat.QCOW2);
363+
if (pool.getPoolType() == Storage.StoragePoolType.RBD) {
364+
restoredVolume.setFormat(Storage.ImageFormat.RAW);
365+
}
342366
restoredVolume.setSize(backupVolumeInfo.getSize());
343367
restoredVolume.setDiskOfferingId(diskOffering.getId());
344368

@@ -347,7 +371,9 @@ public Pair<Boolean, String> restoreBackedUpVolume(Backup backup, Backup.VolumeI
347371
restoreCommand.setBackupRepoType(backupRepository.getType());
348372
restoreCommand.setBackupRepoAddress(backupRepository.getAddress());
349373
restoreCommand.setVmName(vmNameAndState.first());
350-
restoreCommand.setRestoreVolumePaths(Collections.singletonList(String.format("%s/%s", dataStore.getLocalPath(), volumeUUID)));
374+
restoreCommand.setRestoreVolumePaths(Collections.singletonList(String.format("%s%s", storagePoolHost != null ? storagePoolHost.getLocalPath() + "/" : "", volumeUUID)));
375+
DataStore dataStore = dataStoreMgr.getDataStore(pool.getId(), DataStoreRole.Primary);
376+
restoreCommand.setRestoreVolumePools(Collections.singletonList(dataStore != null ? (PrimaryDataStoreTO)dataStore.getTO() : null));
351377
restoreCommand.setDiskType(backupVolumeInfo.getType().name().toLowerCase(Locale.ROOT));
352378
restoreCommand.setMountOptions(backupRepository.getMountOptions());
353379
restoreCommand.setVmExists(null);

0 commit comments

Comments
 (0)