Skip to content

Commit 46e95a6

Browse files
sureshanapartidhslove
authored andcommitted
Update physical size for the snapshots of the volumes on ceph primary storage (apache#12465)
1 parent e4b6ac7 commit 46e95a6

4 files changed

Lines changed: 118 additions & 35 deletions

File tree

core/src/main/java/org/apache/cloudstack/storage/to/SnapshotObjectTO.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ public class SnapshotObjectTO extends DownloadableObjectTO implements DataTO {
5050
private String vmSnapshotName;
5151

5252
public SnapshotObjectTO() {
53-
5453
}
5554

5655
@Override

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,13 +400,16 @@ public void processEvent(ObjectInDataStoreStateMachine.Event event, Answer answe
400400
if (answer instanceof CreateObjectAnswer) {
401401
SnapshotObjectTO snapshotTO = (SnapshotObjectTO)((CreateObjectAnswer)answer).getData();
402402
snapshotStore.setInstallPath(snapshotTO.getPath());
403+
if (snapshotTO.getPhysicalSize() != null && snapshotTO.getPhysicalSize() > 0L) {
404+
snapshotStore.setPhysicalSize(snapshotTO.getPhysicalSize());
405+
}
403406
snapshotStoreDao.update(snapshotStore.getId(), snapshotStore);
404407
} else if (answer instanceof CopyCmdAnswer) {
405408
SnapshotObjectTO snapshotTO = (SnapshotObjectTO)((CopyCmdAnswer)answer).getNewData();
406409
snapshotStore.setInstallPath(snapshotTO.getPath());
407410
if (snapshotTO.getPhysicalSize() != null) {
408411
// For S3 delta snapshot, physical size is currently not set
409-
snapshotStore.setPhysicalSize(snapshotTO.getPhysicalSize());
412+
snapshotStore.setPhysicalSize(snapshotTO.getPhysicalSize());
410413
}
411414
if (snapshotTO.getParentSnapshotPath() == null) {
412415
snapshotStore.setParentSnapshotId(0L);

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2143,7 +2143,7 @@ protected static boolean isInterface(final String fname) {
21432143
for (final String ifNamePattern : ifNamePatterns) {
21442144
commonPattern.append("|(").append(ifNamePattern).append(".*)");
21452145
}
2146-
if(fname.matches(commonPattern.toString())) {
2146+
if (fname.matches(commonPattern.toString())) {
21472147
return true;
21482148
}
21492149
return false;
@@ -2724,11 +2724,10 @@ private String getBroadcastUriFromBridge(final String brName) {
27242724
final Pattern pattern = Pattern.compile("(\\D+)(\\d+)(\\D*)(\\d*)(\\D*)(\\d*)");
27252725
final Matcher matcher = pattern.matcher(pif);
27262726
LOGGER.debug("getting broadcast uri for pif " + pif + " and bridge " + brName);
2727-
if(matcher.find()) {
2727+
if (matcher.find()) {
27282728
if (brName.startsWith("brvx")){
27292729
return BroadcastDomainType.Vxlan.toUri(matcher.group(2)).toString();
2730-
}
2731-
else{
2730+
} else {
27322731
if (!matcher.group(6).isEmpty()) {
27332732
return BroadcastDomainType.Vlan.toUri(matcher.group(6)).toString();
27342733
} else if (!matcher.group(4).isEmpty()) {
@@ -4192,7 +4191,7 @@ public int compare(final DiskTO arg0, final DiskTO arg1) {
41924191
} else if (volume.getType() == Volume.Type.DATADISK) {
41934192
final KVMPhysicalDisk physicalDisk = storagePoolManager.getPhysicalDisk(store.getPoolType(), store.getUuid(), data.getPath());
41944193
final KVMStoragePool pool = physicalDisk.getPool();
4195-
if(StoragePoolType.RBD.equals(pool.getType())) {
4194+
if (StoragePoolType.RBD.equals(pool.getType())) {
41964195
final int devId = volume.getDiskSeq().intValue();
41974196
final String device = mapRbdDevice(physicalDisk,false);
41984197
if (device != null) {
@@ -5848,7 +5847,7 @@ protected long getMemoryFreeInKBs(Domain dm) throws LibvirtException {
58485847
}
58495848

58505849
for (int i = 0; i < memoryStats.length; i++) {
5851-
if(memoryStats[i].getTag() == UNUSEDMEMORY) {
5850+
if (memoryStats[i].getTag() == UNUSEDMEMORY) {
58525851
freeMemory = memoryStats[i].getValue();
58535852
break;
58545853
}

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

Lines changed: 109 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@
5555

5656
import com.cloud.agent.api.Command;
5757
import com.cloud.hypervisor.kvm.resource.LibvirtXMLParser;
58+
import com.fasterxml.jackson.core.JsonProcessingException;
59+
import com.fasterxml.jackson.databind.JsonNode;
60+
import com.fasterxml.jackson.databind.ObjectMapper;
5861
import org.apache.cloudstack.agent.directdownload.DirectDownloadAnswer;
5962
import org.apache.cloudstack.agent.directdownload.DirectDownloadCommand;
6063
import org.apache.cloudstack.direct.download.DirectDownloadHelper;
@@ -368,7 +371,16 @@ public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) {
368371
final TemplateObjectTO newTemplate = new TemplateObjectTO();
369372
newTemplate.setPath(primaryVol.getName());
370373
newTemplate.setSize(primaryVol.getSize());
371-
newTemplate.setFormat(getFormat(primaryPool.getType()));
374+
375+
if (List.of(
376+
StoragePoolType.RBD,
377+
StoragePoolType.PowerFlex,
378+
StoragePoolType.Linstor,
379+
StoragePoolType.FiberChannel).contains(primaryPool.getType())) {
380+
newTemplate.setFormat(ImageFormat.RAW);
381+
} else {
382+
newTemplate.setFormat(ImageFormat.QCOW2);
383+
}
372384
data = newTemplate;
373385
} else if (destData.getObjectType() == DataObjectType.VOLUME) {
374386
final VolumeObjectTO volumeObjectTO = new VolumeObjectTO();
@@ -757,7 +769,7 @@ public Answer createTemplateFromVolume(final CopyCommand cmd) {
757769
templateContent += "snapshot.name=" + dateFormat.format(date) + System.getProperty("line.separator");
758770

759771

760-
try(FileOutputStream templFo = new FileOutputStream(templateProp);){
772+
try (FileOutputStream templFo = new FileOutputStream(templateProp);) {
761773
templFo.write(templateContent.getBytes());
762774
templFo.flush();
763775
} catch (final IOException e) {
@@ -822,11 +834,9 @@ private Answer createTemplateFromVolumeOrSnapshot(CopyCommand cmd) {
822834

823835
if (srcData instanceof VolumeObjectTO) {
824836
isVolume = true;
825-
}
826-
else if (srcData instanceof SnapshotObjectTO) {
837+
} else if (srcData instanceof SnapshotObjectTO) {
827838
isVolume = false;
828-
}
829-
else {
839+
} else {
830840
return new CopyCmdAnswer("unsupported object type");
831841
}
832842

@@ -892,8 +902,7 @@ else if (srcData instanceof SnapshotObjectTO) {
892902

893903
if (isVolume) {
894904
templateContent += "volume.name=" + dateFormat.format(date) + System.getProperty("line.separator");
895-
}
896-
else {
905+
} else {
897906
templateContent += "snapshot.name=" + dateFormat.format(date) + System.getProperty("line.separator");
898907
}
899908

@@ -931,8 +940,7 @@ else if (srcData instanceof SnapshotObjectTO) {
931940
} catch (Exception ex) {
932941
if (isVolume) {
933942
logger.debug("Failed to create template from volume: ", ex);
934-
}
935-
else {
943+
} else {
936944
logger.debug("Failed to create template from snapshot: ", ex);
937945
}
938946

@@ -1093,7 +1101,7 @@ public Answer backupSnapshot(final CopyCommand cmd) {
10931101
q.convert(srcFile, destFile);
10941102

10951103
final File snapFile = new File(snapshotFile);
1096-
if(snapFile.exists()) {
1104+
if (snapFile.exists()) {
10971105
size = snapFile.length();
10981106
}
10991107

@@ -1127,7 +1135,7 @@ public Answer backupSnapshot(final CopyCommand cmd) {
11271135
return new CopyCmdAnswer(result);
11281136
}
11291137
final File snapFile = new File(snapshotDestPath + "/" + descName);
1130-
if(snapFile.exists()){
1138+
if (snapFile.exists()) {
11311139
size = snapFile.length();
11321140
}
11331141
}
@@ -1473,7 +1481,7 @@ protected synchronized void attachOrDetachDisk(final Connect conn, final boolean
14731481
if (resource.getHypervisorType() == Hypervisor.HypervisorType.LXC) {
14741482
final String device = resource.mapRbdDevice(attachingDisk, kvdoEnable);
14751483
if (device != null) {
1476-
logger.debug("RBD device on host is: "+device);
1484+
logger.debug("RBD device on host is: " + device);
14771485
attachingDisk.setPath(device);
14781486
} else {
14791487
throw new InternalErrorException("Error while mapping disk "+attachingDisk.getPath()+" on host");
@@ -1516,11 +1524,11 @@ protected synchronized void attachOrDetachDisk(final Connect conn, final boolean
15161524
}
15171525
diskdef.setSerial(serial);
15181526
if (attachingPool.getType() == StoragePoolType.RBD) {
1519-
if(resource.getHypervisorType() == Hypervisor.HypervisorType.LXC){
1527+
if (resource.getHypervisorType() == Hypervisor.HypervisorType.LXC) {
15201528
// For LXC, map image to host and then attach to Vm
15211529
final String device = resource.mapRbdDevice(attachingDisk, false);
15221530
if (device != null) {
1523-
logger.debug("RBD device on host is: "+device);
1531+
logger.debug("RBD device on host is: " + device);
15241532
diskdef.defBlockBasedDisk(device, devId, busT);
15251533
} else {
15261534
throw new InternalErrorException("Error while mapping disk "+attachingDisk.getPath()+" on host");
@@ -1605,7 +1613,7 @@ protected synchronized void attachOrDetachDisk(final Connect conn, final boolean
16051613
if ((iopsWriteRateMaxLength != null) && (iopsWriteRateMaxLength > 0)) {
16061614
diskdef.setIopsWriteRateMaxLength(iopsWriteRateMaxLength);
16071615
}
1608-
if(cacheMode != null) {
1616+
if (cacheMode != null) {
16091617
diskdef.setCacheMode(DiskDef.DiskCacheMode.valueOf(cacheMode.toUpperCase()));
16101618
}
16111619

@@ -1822,7 +1830,7 @@ public Answer createVolume(final CreateObjectCommand cmd) {
18221830
}
18231831

18241832
final VolumeObjectTO newVol = new VolumeObjectTO();
1825-
if(vol != null) {
1833+
if (vol != null) {
18261834
newVol.setPath(vol.getName());
18271835
if (vol.getQemuEncryptFormat() != null) {
18281836
newVol.setEncryptFormat(vol.getQemuEncryptFormat().toString());
@@ -1918,17 +1926,64 @@ public Answer createSnapshot(final CreateObjectCommand cmd) {
19181926

19191927
String diskPath = disk.getPath();
19201928
String snapshotPath = diskPath + File.separator + snapshotName;
1921-
SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
1922-
if (DomainInfo.DomainState.VIR_DOMAIN_RUNNING.equals(state) && !primaryPool.isExternalSnapshot()) {
1923-
if (snapshotTO.isKvmIncrementalSnapshot()) {
1924-
newSnapshot = takeIncrementalVolumeSnapshotOfRunningVm(snapshotTO, primaryPool, secondaryPool, imageStoreTo != null ? imageStoreTo.getUrl() : null, snapshotName, volume, vm, conn, cmd.getWait());
1925-
} else {
1926-
newSnapshot = takeFullVolumeSnapshotOfRunningVm(cmd, primaryPool, secondaryPool, disk, snapshotName, conn, vmName, diskPath, vm, volume, snapshotPath);
1929+
Long snapshotSize = null;
1930+
if (state == DomainInfo.DomainState.VIR_DOMAIN_RUNNING && !primaryPool.isExternalSnapshot()) {
1931+
1932+
validateAvailableSizeOnPoolToTakeVolumeSnapshot(primaryPool, disk);
1933+
1934+
try {
1935+
snapshotPath = getSnapshotPathInPrimaryStorage(primaryPool.getLocalPath(), snapshotName);
1936+
1937+
String diskLabel = takeVolumeSnapshot(resource.getDisks(conn, vmName), snapshotName, diskPath, vm);
1938+
String convertResult = convertBaseFileToSnapshotFileInPrimaryStorageDir(primaryPool, disk, snapshotPath, volume, cmd.getWait());
1939+
1940+
mergeSnapshotIntoBaseFile(vm, diskLabel, diskPath, snapshotName, volume, conn);
1941+
1942+
validateConvertResult(convertResult, snapshotPath);
1943+
} catch (LibvirtException e) {
1944+
if (!e.getMessage().contains(LIBVIRT_OPERATION_NOT_SUPPORTED_MESSAGE)) {
1945+
throw e;
1946+
}
1947+
1948+
logger.info(String.format("It was not possible to take live disk snapshot for volume [%s], in VM [%s], due to [%s]. We will take full snapshot of the VM"
1949+
+ " and extract the disk instead. Consider upgrading your QEMU binary.", volume, vmName, e.getMessage()));
1950+
1951+
takeFullVmSnapshotForBinariesThatDoesNotSupportLiveDiskSnapshot(vm, snapshotName, vmName);
1952+
primaryPool.createFolder(TemplateConstants.DEFAULT_SNAPSHOT_ROOT_DIR);
1953+
extractDiskFromFullVmSnapshot(disk, volume, snapshotPath, snapshotName, vmName, vm);
1954+
}
1955+
1956+
/*
1957+
* libvirt on RHEL6 doesn't handle resume event emitted from
1958+
* qemu
1959+
*/
1960+
vm = resource.getDomain(conn, vmName);
1961+
state = vm.getInfo().state;
1962+
if (state == DomainInfo.DomainState.VIR_DOMAIN_PAUSED) {
1963+
vm.resume();
19271964
}
19281965
} else {
19291966
if (primaryPool.getType() == StoragePoolType.RBD) {
1930-
takeRbdVolumeSnapshotOfStoppedVm(primaryPool, disk, snapshotName);
1931-
newSnapshot.setPath(snapshotPath);
1967+
try {
1968+
Rados r = radosConnect(primaryPool);
1969+
1970+
final IoCTX io = r.ioCtxCreate(primaryPool.getSourceDir());
1971+
final Rbd rbd = new Rbd(io);
1972+
final RbdImage image = rbd.open(disk.getName());
1973+
1974+
logger.debug("Attempting to create RBD snapshot " + disk.getName() + "@" + snapshotName);
1975+
image.snapCreate(snapshotName);
1976+
1977+
long rbdSnapshotSize = getRbdSnapshotSize(primaryPool.getSourceDir(), disk.getName(), snapshotName, primaryPool.getSourceHost(), primaryPool.getAuthUserName(), primaryPool.getAuthSecret());
1978+
if (rbdSnapshotSize > 0) {
1979+
snapshotSize = rbdSnapshotSize;
1980+
}
1981+
1982+
rbd.close(image);
1983+
r.ioCtxDestroy(io);
1984+
} catch (final Exception e) {
1985+
logger.error("A RBD snapshot operation on " + disk.getName() + " failed. The error was: " + e.getMessage());
1986+
}
19321987
} else if (primaryPool.getType() == StoragePoolType.CLVM) {
19331988
CreateObjectAnswer result = takeClvmVolumeSnapshotOfStoppedVm(disk, snapshotName);
19341989
if (result != null) return result;
@@ -1942,8 +1997,10 @@ public Answer createSnapshot(final CreateObjectCommand cmd) {
19421997
}
19431998
}
19441999

1945-
if (secondaryPool != null) {
1946-
storagePoolMgr.deleteStoragePool(secondaryPool.getType(), secondaryPool.getUuid());
2000+
final SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
2001+
newSnapshot.setPath(snapshotPath);
2002+
if (snapshotSize != null) {
2003+
newSnapshot.setPhysicalSize(snapshotSize);
19472004
}
19482005

19492006
return new CreateObjectAnswer(newSnapshot);
@@ -2454,6 +2511,31 @@ private Pair<String, String> getFullSnapshotOrCheckpointPathAndDirPathOnCorrectS
24542511
return new Pair<>(fullSnapshotPath, dirPath);
24552512
}
24562513

2514+
private long getRbdSnapshotSize(String poolPath, String diskName, String snapshotName, String rbdMonitor, String authUser, String authSecret) {
2515+
logger.debug("Get RBD snapshot size for {}/{}@{}", poolPath, diskName, snapshotName);
2516+
//cmd: rbd du <pool>/<disk-name>@<snapshot-name> --format json --mon-host <monitor-host> --id <user> --key <key> 2>/dev/null
2517+
String snapshotDetailsInJson = Script.runSimpleBashScript(String.format("rbd du %s/%s@%s --format json --mon-host %s --id %s --key %s 2>/dev/null", poolPath, diskName, snapshotName, rbdMonitor, authUser, authSecret));
2518+
if (StringUtils.isNotBlank(snapshotDetailsInJson)) {
2519+
ObjectMapper mapper = new ObjectMapper();
2520+
try {
2521+
JsonNode root = mapper.readTree(snapshotDetailsInJson);
2522+
for (JsonNode image : root.path("images")) {
2523+
if (snapshotName.equals(image.path("snapshot").asText())) {
2524+
long usedSizeInBytes = image.path("used_size").asLong();
2525+
logger.debug("RBD snapshot {}/{}@{} used size in bytes: {}", poolPath, diskName, snapshotName, usedSizeInBytes);
2526+
return usedSizeInBytes;
2527+
}
2528+
}
2529+
} catch (JsonProcessingException e) {
2530+
logger.error("Unable to get the RBD snapshot size, RBD snapshot cmd output: {}", snapshotDetailsInJson, e);
2531+
}
2532+
} else {
2533+
logger.warn("Failed to get RBD snapshot size for {}/{}@{} - no output for RBD snapshot cmd", poolPath, diskName, snapshotName);
2534+
}
2535+
2536+
return 0;
2537+
}
2538+
24572539
protected void deleteFullVmSnapshotAfterConvertingItToExternalDiskSnapshot(Domain vm, String snapshotName, VolumeObjectTO volume, String vmName) throws LibvirtException {
24582540
logger.debug(String.format("Deleting full Instance Snapshot [%s] of Instance [%s] as we already converted it to an external disk Snapshot of the volume [%s].", snapshotName, vmName,
24592541
volume));

0 commit comments

Comments
 (0)