Skip to content

Commit a1a3aff

Browse files
committed
Merge remote-tracking branch 'origin/4.15' into main
2 parents 5837f90 + 961e85e commit a1a3aff

File tree

8 files changed

+200
-42
lines changed

8 files changed

+200
-42
lines changed

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
import com.cloud.storage.Snapshot;
120120
import com.cloud.storage.Storage;
121121
import com.cloud.storage.Storage.ImageFormat;
122+
import com.cloud.storage.Storage.StoragePoolType;
122123
import com.cloud.storage.StorageManager;
123124
import com.cloud.storage.StoragePool;
124125
import com.cloud.storage.VMTemplateStorageResourceAssoc;
@@ -131,6 +132,7 @@
131132
import com.cloud.storage.dao.VMTemplateDetailsDao;
132133
import com.cloud.storage.dao.VolumeDao;
133134
import com.cloud.storage.dao.VolumeDetailsDao;
135+
import com.cloud.storage.snapshot.SnapshotManager;
134136
import com.cloud.template.TemplateManager;
135137
import com.cloud.template.VirtualMachineTemplate;
136138
import com.cloud.user.Account;
@@ -491,18 +493,11 @@ public VolumeInfo createVolumeFromSnapshot(Volume volume, Snapshot snapshot, Use
491493
if (snapInfo == null) {
492494
throw new CloudRuntimeException("Cannot find snapshot " + snapshot.getId());
493495
}
494-
// We need to copy the snapshot onto secondary.
495-
SnapshotStrategy snapshotStrategy = _storageStrategyFactory.getSnapshotStrategy(snapshot, SnapshotOperation.BACKUP);
496-
snapshotStrategy.backupSnapshot(snapInfo);
497496

498-
// Attempt to grab it again.
499-
snapInfo = snapshotFactory.getSnapshot(snapshot.getId(), dataStoreRole);
500-
if (snapInfo == null) {
501-
throw new CloudRuntimeException("Cannot find snapshot " + snapshot.getId() + " on secondary and could not create backup");
502-
}
497+
snapInfo = backupSnapshotIfNeeded(snapshot, dataStoreRole, snapInfo);
503498
}
504499
// don't try to perform a sync if the DataStoreRole of the snapshot is equal to DataStoreRole.Primary
505-
if (!DataStoreRole.Primary.equals(dataStoreRole)) {
500+
if (!DataStoreRole.Primary.equals(snapInfo.getDataStore().getRole())) {
506501
try {
507502
// sync snapshot to region store if necessary
508503
DataStore snapStore = snapInfo.getDataStore();
@@ -534,6 +529,25 @@ public VolumeInfo createVolumeFromSnapshot(Volume volume, Snapshot snapshot, Use
534529

535530
}
536531

532+
private SnapshotInfo backupSnapshotIfNeeded(Snapshot snapshot, DataStoreRole dataStoreRole, SnapshotInfo snapInfo) {
533+
boolean backupSnapToSecondary = SnapshotManager.BackupSnapshotAfterTakingSnapshot.value() == null || SnapshotManager.BackupSnapshotAfterTakingSnapshot.value();
534+
535+
StoragePoolVO srcPool = _storagePoolDao.findById(snapInfo.getBaseVolume().getPoolId());
536+
// We need to copy the snapshot onto secondary.
537+
//Skipping the backup to secondary storage with NFS/FS could be supported when CLOUDSTACK-5297 is accepted with small enhancement in:
538+
//KVMStorageProcessor::createVolumeFromSnapshot and CloudStackPrimaryDataStoreDriverImpl::copyAsync/createAsync
539+
if ((!backupSnapToSecondary && (StoragePoolType.NetworkFilesystem.equals(srcPool.getPoolType()) || StoragePoolType.Filesystem.equals(srcPool.getPoolType())))) {
540+
SnapshotStrategy snapshotStrategy = _storageStrategyFactory.getSnapshotStrategy(snapshot, SnapshotOperation.BACKUP);
541+
snapshotStrategy.backupSnapshot(snapInfo);
542+
// Attempt to grab it again.
543+
snapInfo = snapshotFactory.getSnapshot(snapshot.getId(), dataStoreRole);
544+
if (snapInfo == null) {
545+
throw new CloudRuntimeException("Cannot find snapshot " + snapshot.getId() + " on secondary and could not create backup");
546+
}
547+
}
548+
return snapInfo;
549+
}
550+
537551
public DataStoreRole getDataStoreRole(Snapshot snapshot) {
538552
SnapshotDataStoreVO snapshotStore = _snapshotDataStoreDao.findBySnapshot(snapshot.getId(), DataStoreRole.Primary);
539553

engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDao.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ public interface SnapshotDataStoreDao extends GenericDao<SnapshotDataStoreVO, Lo
6868

6969
SnapshotDataStoreVO findByVolume(long volumeId, DataStoreRole role);
7070

71+
SnapshotDataStoreVO findByVolume(long snapshotId, long volumeId, DataStoreRole role);
72+
7173
/**
7274
* List all snapshots in 'snapshot_store_ref' by volume and data store role. Therefore, it is possible to list all snapshots that are in the primary storage or in the secondary storage.
7375
*/

engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ public SnapshotInfo getSnapshot(long snapshotId, DataStoreRole role) {
9292
}
9393
SnapshotDataStoreVO snapshotStore = snapshotStoreDao.findBySnapshot(snapshotId, role);
9494
if (snapshotStore == null) {
95-
snapshotStore = snapshotStoreDao.findByVolume(snapshot.getVolumeId(), role);
95+
snapshotStore = snapshotStoreDao.findByVolume(snapshotId, snapshot.getVolumeId(), role);
9696
if (snapshotStore == null) {
9797
return null;
9898
}

engine/storage/src/main/java/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ public boolean configure(String name, Map<String, Object> params) throws Configu
142142
volumeSearch = createSearchBuilder();
143143
volumeSearch.and("volume_id", volumeSearch.entity().getVolumeId(), SearchCriteria.Op.EQ);
144144
volumeSearch.and("store_role", volumeSearch.entity().getRole(), SearchCriteria.Op.EQ);
145+
volumeSearch.and("snapshot_id", volumeSearch.entity().getSnapshotId(), SearchCriteria.Op.EQ);
145146
volumeSearch.done();
146147

147148
stateSearch = createSearchBuilder();
@@ -365,6 +366,15 @@ public SnapshotDataStoreVO findByVolume(long volumeId, DataStoreRole role) {
365366
return findOneBy(sc);
366367
}
367368

369+
@Override
370+
public SnapshotDataStoreVO findByVolume(long snapshotId, long volumeId, DataStoreRole role) {
371+
SearchCriteria<SnapshotDataStoreVO> sc = volumeSearch.create();
372+
sc.setParameters("snapshot_id", snapshotId);
373+
sc.setParameters("volume_id", volumeId);
374+
sc.setParameters("store_role", role);
375+
return findOneBy(sc);
376+
}
377+
368378
@Override
369379
public List<SnapshotDataStoreVO> findBySnapshotId(long snapshotId) {
370380
SearchCriteria<SnapshotDataStoreVO> sc = snapshotIdSearch.create();

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java

Lines changed: 130 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
import com.ceph.rbd.Rbd;
8686
import com.ceph.rbd.RbdException;
8787
import com.ceph.rbd.RbdImage;
88+
import com.ceph.rbd.jna.RbdSnapInfo;
8889
import com.cloud.agent.api.Answer;
8990
import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
9091
import com.cloud.agent.api.to.DataObjectType;
@@ -1635,39 +1636,24 @@ public Answer createVolumeFromSnapshot(final CopyCommand cmd) {
16351636
final DataStoreTO imageStore = srcData.getDataStore();
16361637
final VolumeObjectTO volume = snapshot.getVolume();
16371638

1638-
if (!(imageStore instanceof NfsTO)) {
1639+
if (!(imageStore instanceof NfsTO || imageStore instanceof PrimaryDataStoreTO)) {
16391640
return new CopyCmdAnswer("unsupported protocol");
16401641
}
16411642

1642-
final NfsTO nfsImageStore = (NfsTO)imageStore;
1643-
16441643
final String snapshotFullPath = snapshot.getPath();
16451644
final int index = snapshotFullPath.lastIndexOf("/");
16461645
final String snapshotPath = snapshotFullPath.substring(0, index);
16471646
final String snapshotName = snapshotFullPath.substring(index + 1);
1648-
final KVMStoragePool secondaryPool = storagePoolMgr.getStoragePoolByURI(nfsImageStore.getUrl() + File.separator + snapshotPath);
1649-
final KVMPhysicalDisk snapshotDisk = secondaryPool.getPhysicalDisk(snapshotName);
1650-
1651-
if (volume.getFormat() == ImageFormat.RAW) {
1652-
snapshotDisk.setFormat(PhysicalDiskFormat.RAW);
1653-
} else if (volume.getFormat() == ImageFormat.QCOW2) {
1654-
snapshotDisk.setFormat(PhysicalDiskFormat.QCOW2);
1647+
KVMPhysicalDisk disk = null;
1648+
if (imageStore instanceof NfsTO) {
1649+
disk = createVolumeFromSnapshotOnNFS(cmd, pool, imageStore, volume, snapshotPath, snapshotName);
1650+
} else {
1651+
disk = createVolumeFromRBDSnapshot(cmd, destData, pool, imageStore, volume, snapshotName, disk);
16551652
}
16561653

1657-
final String primaryUuid = pool.getUuid();
1658-
final KVMStoragePool primaryPool = storagePoolMgr.getStoragePool(pool.getPoolType(), primaryUuid);
1659-
final String volUuid = UUID.randomUUID().toString();
1660-
1661-
Map<String, String> details = cmd.getOptions2();
1662-
1663-
String path = details != null ? details.get(DiskTO.IQN) : null;
1664-
1665-
storagePoolMgr.connectPhysicalDisk(pool.getPoolType(), pool.getUuid(), path, details);
1666-
1667-
KVMPhysicalDisk disk = storagePoolMgr.copyPhysicalDisk(snapshotDisk, path != null ? path : volUuid, primaryPool, cmd.getWaitInMillSeconds());
1668-
1669-
storagePoolMgr.disconnectPhysicalDisk(pool.getPoolType(), pool.getUuid(), path);
1670-
1654+
if (disk == null) {
1655+
return new CopyCmdAnswer("Could not create volume from snapshot");
1656+
}
16711657
final VolumeObjectTO newVol = new VolumeObjectTO();
16721658
newVol.setPath(disk.getName());
16731659
newVol.setSize(disk.getVirtualSize());
@@ -1680,6 +1666,126 @@ public Answer createVolumeFromSnapshot(final CopyCommand cmd) {
16801666
}
16811667
}
16821668

1669+
private KVMPhysicalDisk createVolumeFromRBDSnapshot(CopyCommand cmd, DataTO destData,
1670+
PrimaryDataStoreTO pool, DataStoreTO imageStore, VolumeObjectTO volume, String snapshotName, KVMPhysicalDisk disk) {
1671+
PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO) imageStore;
1672+
KVMStoragePool srcPool = storagePoolMgr.getStoragePool(primaryStore.getPoolType(), primaryStore.getUuid());
1673+
KVMPhysicalDisk snapshotDisk = srcPool.getPhysicalDisk(volume.getPath());
1674+
KVMStoragePool destPool = storagePoolMgr.getStoragePool(pool.getPoolType(), pool.getUuid());
1675+
VolumeObjectTO newVol = (VolumeObjectTO) destData;
1676+
1677+
if (StoragePoolType.RBD.equals(primaryStore.getPoolType())) {
1678+
s_logger.debug(String.format("Attempting to create volume from RBD snapshot %s", snapshotName));
1679+
if (StoragePoolType.RBD.equals(pool.getPoolType())) {
1680+
disk = createRBDvolumeFromRBDSnapshot(snapshotDisk, snapshotName, newVol.getUuid(),
1681+
PhysicalDiskFormat.RAW, newVol.getSize(), destPool, cmd.getWaitInMillSeconds());
1682+
s_logger.debug(String.format("Created RBD volume %s from snapshot %s", disk, snapshotDisk));
1683+
} else {
1684+
Map<String, String> details = cmd.getOptions2();
1685+
1686+
String path = details != null ? details.get(DiskTO.IQN) : null;
1687+
1688+
storagePoolMgr.connectPhysicalDisk(pool.getPoolType(), pool.getUuid(), path, details);
1689+
1690+
snapshotDisk.setPath(snapshotDisk.getPath() + "@" + snapshotName);
1691+
disk = storagePoolMgr.copyPhysicalDisk(snapshotDisk, path != null ? path : newVol.getUuid(),
1692+
destPool, cmd.getWaitInMillSeconds());
1693+
1694+
storagePoolMgr.disconnectPhysicalDisk(pool.getPoolType(), pool.getUuid(), path);
1695+
s_logger.debug(String.format("Created RBD volume %s from snapshot %s", disk, snapshotDisk));
1696+
1697+
}
1698+
}
1699+
return disk;
1700+
}
1701+
1702+
private KVMPhysicalDisk createVolumeFromSnapshotOnNFS(CopyCommand cmd, PrimaryDataStoreTO pool,
1703+
DataStoreTO imageStore, VolumeObjectTO volume, String snapshotPath, String snapshotName) {
1704+
NfsTO nfsImageStore = (NfsTO)imageStore;
1705+
KVMStoragePool secondaryPool = storagePoolMgr.getStoragePoolByURI(nfsImageStore.getUrl() + File.separator + snapshotPath);
1706+
KVMPhysicalDisk snapshotDisk = secondaryPool.getPhysicalDisk(snapshotName);
1707+
if (volume.getFormat() == ImageFormat.RAW) {
1708+
snapshotDisk.setFormat(PhysicalDiskFormat.RAW);
1709+
} else if (volume.getFormat() == ImageFormat.QCOW2) {
1710+
snapshotDisk.setFormat(PhysicalDiskFormat.QCOW2);
1711+
}
1712+
1713+
final String primaryUuid = pool.getUuid();
1714+
final KVMStoragePool primaryPool = storagePoolMgr.getStoragePool(pool.getPoolType(), primaryUuid);
1715+
final String volUuid = UUID.randomUUID().toString();
1716+
1717+
Map<String, String> details = cmd.getOptions2();
1718+
1719+
String path = details != null ? details.get(DiskTO.IQN) : null;
1720+
1721+
storagePoolMgr.connectPhysicalDisk(pool.getPoolType(), pool.getUuid(), path, details);
1722+
1723+
KVMPhysicalDisk disk = storagePoolMgr.copyPhysicalDisk(snapshotDisk, path != null ? path : volUuid, primaryPool, cmd.getWaitInMillSeconds());
1724+
1725+
storagePoolMgr.disconnectPhysicalDisk(pool.getPoolType(), pool.getUuid(), path);
1726+
return disk;
1727+
}
1728+
1729+
private KVMPhysicalDisk createRBDvolumeFromRBDSnapshot(KVMPhysicalDisk volume, String snapshotName, String name,
1730+
PhysicalDiskFormat format, long size, KVMStoragePool destPool, int timeout) {
1731+
1732+
KVMStoragePool srcPool = volume.getPool();
1733+
KVMPhysicalDisk disk = null;
1734+
String newUuid = name;
1735+
1736+
disk = new KVMPhysicalDisk(destPool.getSourceDir() + "/" + newUuid, newUuid, destPool);
1737+
disk.setFormat(format);
1738+
disk.setSize(size > volume.getVirtualSize() ? size : volume.getVirtualSize());
1739+
disk.setVirtualSize(size > volume.getVirtualSize() ? size : disk.getSize());
1740+
1741+
try {
1742+
1743+
Rados r = new Rados(srcPool.getAuthUserName());
1744+
r.confSet("mon_host", srcPool.getSourceHost() + ":" + srcPool.getSourcePort());
1745+
r.confSet("key", srcPool.getAuthSecret());
1746+
r.confSet("client_mount_timeout", "30");
1747+
r.connect();
1748+
1749+
IoCTX io = r.ioCtxCreate(srcPool.getSourceDir());
1750+
Rbd rbd = new Rbd(io);
1751+
RbdImage srcImage = rbd.open(volume.getName());
1752+
1753+
List<RbdSnapInfo> snaps = srcImage.snapList();
1754+
boolean snapFound = false;
1755+
for (RbdSnapInfo snap : snaps) {
1756+
if (snapshotName.equals(snap.name)) {
1757+
snapFound = true;
1758+
break;
1759+
}
1760+
}
1761+
1762+
if (!snapFound) {
1763+
s_logger.debug(String.format("Could not find snapshot %s on RBD", snapshotName));
1764+
return null;
1765+
}
1766+
srcImage.snapProtect(snapshotName);
1767+
1768+
s_logger.debug(String.format("Try to clone snapshot %s on RBD", snapshotName));
1769+
rbd.clone(volume.getName(), snapshotName, io, disk.getName(), LibvirtStorageAdaptor.RBD_FEATURES, 0);
1770+
RbdImage diskImage = rbd.open(disk.getName());
1771+
if (disk.getVirtualSize() > volume.getVirtualSize()) {
1772+
diskImage.resize(disk.getVirtualSize());
1773+
}
1774+
1775+
diskImage.flatten();
1776+
rbd.close(diskImage);
1777+
1778+
srcImage.snapUnprotect(snapshotName);
1779+
rbd.close(srcImage);
1780+
r.ioCtxDestroy(io);
1781+
} catch (RadosException | RbdException e) {
1782+
s_logger.error(String.format("Failed due to %s", e.getMessage()), e);
1783+
disk = null;
1784+
}
1785+
1786+
return disk;
1787+
}
1788+
16831789
@Override
16841790
public Answer deleteSnapshot(final DeleteCommand cmd) {
16851791
String snap_full_name = "";

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
8181
private static final int RBD_FEATURE_OBJECT_MAP = 8;
8282
private static final int RBD_FEATURE_FAST_DIFF = 16;
8383
private static final int RBD_FEATURE_DEEP_FLATTEN = 32;
84-
private int rbdFeatures = RBD_FEATURE_LAYERING + RBD_FEATURE_EXCLUSIVE_LOCK + RBD_FEATURE_OBJECT_MAP + RBD_FEATURE_FAST_DIFF + RBD_FEATURE_DEEP_FLATTEN;
84+
public static final int RBD_FEATURES = RBD_FEATURE_LAYERING + RBD_FEATURE_EXCLUSIVE_LOCK + RBD_FEATURE_OBJECT_MAP + RBD_FEATURE_FAST_DIFF + RBD_FEATURE_DEEP_FLATTEN;
8585
private int rbdOrder = 0; /* Order 0 means 4MB blocks (the default) */
8686

8787
private static final Set<StoragePoolType> poolTypesThatEnableCreateDiskFromTemplateBacking = new HashSet<>(Arrays.asList(StoragePoolType.NetworkFilesystem,
@@ -1116,7 +1116,7 @@ private KVMPhysicalDisk createDiskFromTemplateOnRBD(KVMPhysicalDisk template,
11161116
s_logger.debug("The source image " + srcPool.getSourceDir() + "/" + template.getName() +
11171117
" is RBD format 1. We have to perform a regular copy (" + toHumanReadableSize(disk.getVirtualSize()) + " bytes)");
11181118

1119-
rbd.create(disk.getName(), disk.getVirtualSize(), rbdFeatures, rbdOrder);
1119+
rbd.create(disk.getName(), disk.getVirtualSize(), RBD_FEATURES, rbdOrder);
11201120
RbdImage destImage = rbd.open(disk.getName());
11211121

11221122
s_logger.debug("Starting to copy " + srcImage.getName() + " to " + destImage.getName() + " in Ceph pool " + srcPool.getSourceDir());
@@ -1153,7 +1153,7 @@ private KVMPhysicalDisk createDiskFromTemplateOnRBD(KVMPhysicalDisk template,
11531153
srcImage.snapProtect(rbdTemplateSnapName);
11541154
}
11551155

1156-
rbd.clone(template.getName(), rbdTemplateSnapName, io, disk.getName(), rbdFeatures, rbdOrder);
1156+
rbd.clone(template.getName(), rbdTemplateSnapName, io, disk.getName(), RBD_FEATURES, rbdOrder);
11571157
s_logger.debug("Succesfully cloned " + template.getName() + "@" + rbdTemplateSnapName + " to " + disk.getName());
11581158
/* We also need to resize the image if the VM was deployed with a larger root disk size */
11591159
if (disk.getVirtualSize() > template.getVirtualSize()) {
@@ -1193,7 +1193,7 @@ private KVMPhysicalDisk createDiskFromTemplateOnRBD(KVMPhysicalDisk template,
11931193

11941194
s_logger.debug("Creating " + disk.getName() + " on the destination cluster " + rDest.confGet("mon_host") + " in pool " +
11951195
destPool.getSourceDir());
1196-
dRbd.create(disk.getName(), disk.getVirtualSize(), rbdFeatures, rbdOrder);
1196+
dRbd.create(disk.getName(), disk.getVirtualSize(), RBD_FEATURES, rbdOrder);
11971197

11981198
RbdImage srcImage = sRbd.open(template.getName());
11991199
RbdImage destImage = dRbd.open(disk.getName());

0 commit comments

Comments
 (0)