Skip to content

Commit 22c4934

Browse files
committed
Add support for incremental volume snapshots for clvm_ng
1 parent 348cf33 commit 22c4934

File tree

5 files changed

+77
-28
lines changed

5 files changed

+77
-28
lines changed

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtClvmLockTransferCommandWrapper.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ public Answer execute(ClvmLockTransferCommand cmd, LibvirtComputingResource serv
3939
ClvmLockTransferCommand.Operation operation = cmd.getOperation();
4040
String volumeUuid = cmd.getVolumeUuid();
4141

42-
logger.info(String.format("Executing CLVM lock transfer: operation=%s, lv=%s, volume=%s",
43-
operation, lvPath, volumeUuid));
42+
logger.info("Executing CLVM lock transfer: operation={}, lv={}, volume={}",
43+
operation, lvPath, volumeUuid);
4444

4545
try {
4646
String lvchangeOpt;
@@ -69,20 +69,20 @@ public Answer execute(ClvmLockTransferCommand cmd, LibvirtComputingResource serv
6969
String result = script.execute();
7070

7171
if (result != null) {
72-
logger.error("CLVM lock transfer failed for volume {}: {}}",
72+
logger.error("CLVM lock transfer failed for volume {}: {}",
7373
volumeUuid, result);
7474
return new Answer(cmd, false,
7575
String.format("lvchange %s %s failed: %s", lvchangeOpt, lvPath, result));
7676
}
7777

78-
logger.info("Successfully executed CLVM lock transfer: {} {}} for volume {}}",
78+
logger.info("Successfully executed CLVM lock transfer: {} {} for volume {}",
7979
lvchangeOpt, lvPath, volumeUuid);
8080

8181
return new Answer(cmd, true,
8282
String.format("Successfully %s CLVM volume %s", operationDesc, volumeUuid));
8383

8484
} catch (Exception e) {
85-
logger.error("Exception during CLVM lock transfer for volume {}: {}}",
85+
logger.error("Exception during CLVM lock transfer for volume {}: {}",
8686
volumeUuid, e.getMessage(), e);
8787
return new Answer(cmd, false, "Exception: " + e.getMessage());
8888
}

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

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,26 @@ public class KVMStorageProcessor implements StorageProcessor {
223223
" </devices>\n" +
224224
"</domain>";
225225

226+
private static final String DUMMY_VM_XML_BLOCK = "<domain type='qemu'>\n" +
227+
" <name>%s</name>\n" +
228+
" <memory unit='MiB'>256</memory>\n" +
229+
" <currentMemory unit='MiB'>256</currentMemory>\n" +
230+
" <vcpu>1</vcpu>\n" +
231+
" <os>\n" +
232+
" <type arch='%s' machine='%s'>hvm</type>\n" +
233+
" <boot dev='hd'/>\n" +
234+
" </os>\n" +
235+
" <devices>\n" +
236+
" <emulator>%s</emulator>\n" +
237+
" <disk type='block' device='disk'>\n" +
238+
" <driver name='qemu' type='qcow2' cache='none'/>\n"+
239+
" <source dev='%s'/>\n" +
240+
" <target dev='sda'/>\n" +
241+
" </disk>\n" +
242+
" <graphics type='vnc' port='-1'/>\n" +
243+
" </devices>\n" +
244+
"</domain>";
245+
226246

227247
public KVMStorageProcessor(final KVMStoragePoolManager storagePoolMgr, final LibvirtComputingResource resource) {
228248
this.storagePoolMgr = storagePoolMgr;
@@ -2038,9 +2058,21 @@ public Answer createSnapshot(final CreateObjectCommand cmd) {
20382058
newSnapshot.setPhysicalSize(snapshotSize);
20392059
}
20402060
} else if (primaryPool.getType() == StoragePoolType.CLVM || primaryPool.getType() == StoragePoolType.CLVM_NG) {
2041-
CreateObjectAnswer result = takeClvmVolumeSnapshotOfStoppedVm(disk, snapshotName);
2042-
if (result != null) return result;
2043-
newSnapshot.setPath(snapshotPath);
2061+
if (primaryPool.getType() == StoragePoolType.CLVM_NG && snapshotTO.isKvmIncrementalSnapshot()) {
2062+
if (secondaryPool == null) {
2063+
String errorMsg = String.format("Incremental snapshots for CLVM_NG require secondary storage. " +
2064+
"Please configure secondary storage or disable incremental snapshots for volume [%s].", volume.getName());
2065+
logger.error(errorMsg);
2066+
return new CreateObjectAnswer(errorMsg);
2067+
}
2068+
logger.info("Taking incremental snapshot of CLVM_NG volume [{}] using QCOW2 backup to secondary storage.", volume.getName());
2069+
newSnapshot = takeIncrementalVolumeSnapshotOfStoppedVm(snapshotTO, primaryPool, secondaryPool,
2070+
imageStoreTo.getUrl(), snapshotName, volume, conn, cmd.getWait());
2071+
} else {
2072+
CreateObjectAnswer result = takeClvmVolumeSnapshotOfStoppedVm(disk, snapshotName);
2073+
if (result != null) return result;
2074+
newSnapshot.setPath(snapshotPath);
2075+
}
20442076
} else {
20452077
if (snapshotTO.isKvmIncrementalSnapshot()) {
20462078
newSnapshot = takeIncrementalVolumeSnapshotOfStoppedVm(snapshotTO, primaryPool, secondaryPool, imageStoreTo != null ? imageStoreTo.getUrl() : null, snapshotName, volume, conn, cmd.getWait());
@@ -2113,7 +2145,11 @@ private String getVmXml(KVMStoragePool primaryPool, VolumeObjectTO volumeObjectT
21132145
String machine = resource.isGuestAarch64() ? LibvirtComputingResource.VIRT : LibvirtComputingResource.PC;
21142146
String cpuArch = resource.getGuestCpuArch() != null ? resource.getGuestCpuArch() : "x86_64";
21152147

2116-
return String.format(DUMMY_VM_XML, vmName, cpuArch, machine, resource.getHypervisorPath(), primaryPool.getLocalPathFor(volumeObjectTo.getPath()));
2148+
String volumePath = primaryPool.getLocalPathFor(volumeObjectTo.getPath());
2149+
boolean isClvmNg = StoragePoolType.CLVM_NG == primaryPool.getType();
2150+
2151+
String xmlTemplate = isClvmNg ? DUMMY_VM_XML_BLOCK : DUMMY_VM_XML;
2152+
return String.format(xmlTemplate, vmName, cpuArch, machine, resource.getHypervisorPath(), volumePath);
21172153
}
21182154

21192155
private SnapshotObjectTO takeIncrementalVolumeSnapshotOfRunningVm(SnapshotObjectTO snapshotObjectTO, KVMStoragePool primaryPool, KVMStoragePool secondaryPool,

server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2696,16 +2696,6 @@ private boolean areBothPoolsClvmType(StoragePoolVO volumePool, StoragePoolVO vmP
26962696
vmPool.getPoolType() == StoragePoolType.CLVM;
26972697
}
26982698

2699-
/**
2700-
* Checks if a storage pool is CLVM type.
2701-
*
2702-
* @param pool Storage pool to check
2703-
* @return true if pool is CLVM type
2704-
*/
2705-
private boolean isClvmPool(StoragePoolVO pool) {
2706-
return pool != null && pool.getPoolType() == StoragePoolType.CLVM;
2707-
}
2708-
27092699
/**
27102700
* Extracts the Volume Group (VG) name from a CLVM storage pool path.
27112701
* For CLVM, the path is typically: /vgname
@@ -2797,7 +2787,7 @@ private boolean isClvmLockTransferRequired(VolumeInfo volumeToAttach, VolumeVO v
27972787
StoragePoolVO volumePool = pools.first();
27982788
StoragePoolVO vmPool = pools.second();
27992789

2800-
if (!isClvmPool(volumePool)) {
2790+
if (volumePool != null && !ClvmLockManager.isClvmPoolType(volumePool.getPoolType())) {
28012791
return false;
28022792
}
28032793

server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,15 +1641,16 @@ public SnapshotInfo takeSnapshot(VolumeInfo volume) throws ResourceAllocationExc
16411641
boolean isKvmAndFileBasedStorage = isHypervisorKvmAndFileBasedStorage(volume, storagePool);
16421642
boolean backupSnapToSecondary = isBackupSnapshotToSecondaryForZone(volume.getDataCenterId());
16431643

1644-
if (isKvmAndFileBasedStorage && backupSnapToSecondary) {
1644+
StoragePoolType poolType = volume.getStoragePoolType();
1645+
if ((isKvmAndFileBasedStorage || StoragePoolType.CLVM_NG == poolType) && backupSnapToSecondary) {
16451646
DataStore imageStore = snapshotSrv.findSnapshotImageStore(snapshot);
16461647
if (imageStore == null) {
16471648
throw new CloudRuntimeException(String.format("Could not find any secondary storage to allocate snapshot [%s].", snapshot));
16481649
}
16491650
snapshot.setImageStore(imageStore);
16501651
}
16511652

1652-
updateSnapshotPayload(volume.getPoolId(), payload, isKvmAndFileBasedStorage, clusterId);
1653+
updateSnapshotPayload(volume.getPoolId(), payload, isKvmAndFileBasedStorage, poolType, clusterId);
16531654

16541655
snapshot.addPayload(payload);
16551656
try {
@@ -1664,8 +1665,12 @@ public SnapshotInfo takeSnapshot(VolumeInfo volume) throws ResourceAllocationExc
16641665

16651666
SnapshotInfo snapshotOnPrimary = snapshotStrategy.takeSnapshot(snapshot);
16661667

1668+
// For CLVM_NG with incremental snapshots, the snapshot is already created directly on secondary storage
1669+
boolean isClvmNgIncremental = storagePool.getPoolType() == StoragePoolType.CLVM_NG &&
1670+
snapshot.isKvmIncrementalSnapshot();
1671+
16671672
if (backupSnapToSecondary) {
1668-
if (!isKvmAndFileBasedStorage) {
1673+
if (!isKvmAndFileBasedStorage && !isClvmNgIncremental) {
16691674
backupSnapshotToSecondary(payload.getAsyncBackup(), snapshotStrategy, snapshotOnPrimary, payload.getZoneIds(), payload.getStoragePoolIds());
16701675
if (storagePool.getPoolType() == StoragePoolType.CLVM || storagePool.getPoolType() == StoragePoolType.CLVM_NG) {
16711676
_snapshotStoreDao.removeBySnapshotStore(snapshotId, snapshotOnPrimary.getDataStore().getId(), snapshotOnPrimary.getDataStore().getRole());
@@ -1852,7 +1857,7 @@ private void decriseBackupSnapshotAttempts() {
18521857
}
18531858
}
18541859

1855-
private void updateSnapshotPayload(long storagePoolId, CreateSnapshotPayload payload, boolean isKvmAndFileBasedStorage, Long clusterId) {
1860+
private void updateSnapshotPayload(long storagePoolId, CreateSnapshotPayload payload, boolean isKvmAndFileBasedStorage, StoragePoolType poolType, Long clusterId) {
18561861
StoragePoolVO storagePoolVO = _storagePoolDao.findById(storagePoolId);
18571862

18581863
if (storagePoolVO.isManaged()) {
@@ -1865,7 +1870,7 @@ private void updateSnapshotPayload(long storagePoolId, CreateSnapshotPayload pay
18651870
payload.setLocationType(null);
18661871
}
18671872

1868-
if (isKvmAndFileBasedStorage && kvmIncrementalSnapshot.valueIn(clusterId)) {
1873+
if ((isKvmAndFileBasedStorage || StoragePoolType.CLVM_NG == poolType) && kvmIncrementalSnapshot.valueIn(clusterId)) {
18691874
payload.setKvmIncrementalSnapshot(true);
18701875
}
18711876
}

server/src/main/java/com/cloud/vm/UserVmManagerImpl.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5398,19 +5398,37 @@ public boolean finalizeVirtualMachineProfile(VirtualMachineProfile profile, Depl
53985398

53995399
@Override
54005400
public boolean setupVmForPvlan(boolean add, Long hostId, NicProfile nic) {
5401-
if (!nic.getBroadCastUri().getScheme().equals("pvlan")) {
5401+
if (nic == null) {
5402+
logger.warn("Skipping PVLAN setup on host {} because NIC profile is null", hostId);
5403+
return false;
5404+
}
5405+
5406+
if (nic.getBroadCastUri() == null) {
5407+
logger.debug("Skipping PVLAN setup on host {} for NIC {} because broadcast URI is null", hostId, nic);
5408+
return false;
5409+
}
5410+
5411+
String scheme = nic.getBroadCastUri().getScheme();
5412+
if (!"pvlan".equalsIgnoreCase(scheme)) {
5413+
logger.debug("Skipping PVLAN setup on host {} for NIC {} because broadcast URI scheme is {}", hostId, nic, scheme);
54025414
return false;
54035415
}
54045416
String op = "add";
54055417
if (!add) {
54065418
// "delete" would remove all the rules(if using ovs) related to this vm
54075419
op = "delete";
54085420
}
5409-
Network network = _networkDao.findById(nic.getNetworkId());
5421+
54105422
Host host = _hostDao.findById(hostId);
5423+
if (host == null) {
5424+
logger.warn("Host with id {} does not exist", hostId);
5425+
return false;
5426+
}
5427+
5428+
Network network = _networkDao.findById(nic.getNetworkId());
54115429
String networkTag = _networkModel.getNetworkTag(host.getHypervisorType(), network);
54125430
PvlanSetupCommand cmd = PvlanSetupCommand.createVmSetup(op, nic.getBroadCastUri(), networkTag, nic.getMacAddress());
5413-
Answer answer = null;
5431+
Answer answer;
54145432
try {
54155433
answer = _agentMgr.send(hostId, cmd);
54165434
} catch (OperationTimedoutException e) {

0 commit comments

Comments
 (0)