Skip to content

Commit d98511d

Browse files
Update physical size for the snapshots of the volumes on ceph primary storage (#12465)
1 parent d0e21a7 commit d98511d

File tree

4 files changed

+62
-29
lines changed

4 files changed

+62
-29
lines changed

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,7 @@ public class SnapshotObjectTO extends DownloadableObjectTO implements DataTO {
4444
private Long physicalSize = (long) 0;
4545
private long accountId;
4646

47-
4847
public SnapshotObjectTO() {
49-
5048
}
5149

5250
public SnapshotObjectTO(SnapshotInfo snapshot) {

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
@@ -358,13 +358,16 @@ public void processEvent(ObjectInDataStoreStateMachine.Event event, Answer answe
358358
if (answer instanceof CreateObjectAnswer) {
359359
SnapshotObjectTO snapshotTO = (SnapshotObjectTO)((CreateObjectAnswer)answer).getData();
360360
snapshotStore.setInstallPath(snapshotTO.getPath());
361+
if (snapshotTO.getPhysicalSize() != null && snapshotTO.getPhysicalSize() > 0L) {
362+
snapshotStore.setPhysicalSize(snapshotTO.getPhysicalSize());
363+
}
361364
snapshotStoreDao.update(snapshotStore.getId(), snapshotStore);
362365
} else if (answer instanceof CopyCmdAnswer) {
363366
SnapshotObjectTO snapshotTO = (SnapshotObjectTO)((CopyCmdAnswer)answer).getNewData();
364367
snapshotStore.setInstallPath(snapshotTO.getPath());
365368
if (snapshotTO.getPhysicalSize() != null) {
366369
// For S3 delta snapshot, physical size is currently not set
367-
snapshotStore.setPhysicalSize(snapshotTO.getPhysicalSize());
370+
snapshotStore.setPhysicalSize(snapshotTO.getPhysicalSize());
368371
}
369372
if (snapshotTO.getParentSnapshotPath() == null) {
370373
snapshotStore.setParentSnapshotId(0L);

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

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1836,7 +1836,7 @@ protected static boolean isInterface(final String fname) {
18361836
for (final String ifNamePattern : ifNamePatterns) {
18371837
commonPattern.append("|(").append(ifNamePattern).append(".*)");
18381838
}
1839-
if(fname.matches(commonPattern.toString())) {
1839+
if (fname.matches(commonPattern.toString())) {
18401840
return true;
18411841
}
18421842
return false;
@@ -2128,11 +2128,10 @@ private String getBroadcastUriFromBridge(final String brName) {
21282128
final Pattern pattern = Pattern.compile("(\\D+)(\\d+)(\\D*)(\\d*)(\\D*)(\\d*)");
21292129
final Matcher matcher = pattern.matcher(pif);
21302130
LOGGER.debug("getting broadcast uri for pif " + pif + " and bridge " + brName);
2131-
if(matcher.find()) {
2131+
if (matcher.find()) {
21322132
if (brName.startsWith("brvx")){
21332133
return BroadcastDomainType.Vxlan.toUri(matcher.group(2)).toString();
2134-
}
2135-
else{
2134+
} else {
21362135
if (!matcher.group(6).isEmpty()) {
21372136
return BroadcastDomainType.Vlan.toUri(matcher.group(6)).toString();
21382137
} else if (!matcher.group(4).isEmpty()) {
@@ -3331,7 +3330,7 @@ public int compare(final DiskTO arg0, final DiskTO arg1) {
33313330
} else if (volume.getType() == Volume.Type.DATADISK) {
33323331
final KVMPhysicalDisk physicalDisk = storagePoolManager.getPhysicalDisk(store.getPoolType(), store.getUuid(), data.getPath());
33333332
final KVMStoragePool pool = physicalDisk.getPool();
3334-
if(StoragePoolType.RBD.equals(pool.getType())) {
3333+
if (StoragePoolType.RBD.equals(pool.getType())) {
33353334
final int devId = volume.getDiskSeq().intValue();
33363335
final String device = mapRbdDevice(physicalDisk);
33373336
if (device != null) {
@@ -4777,7 +4776,7 @@ protected long getMemoryFreeInKBs(Domain dm) throws LibvirtException {
47774776
}
47784777

47794778
for (int i = 0; i < memoryStats.length; i++) {
4780-
if(memoryStats[i].getTag() == UNUSEDMEMORY) {
4779+
if (memoryStats[i].getTag() == UNUSEDMEMORY) {
47814780
freeMemory = memoryStats[i].getValue();
47824781
break;
47834782
}
@@ -5243,12 +5242,12 @@ public HypervisorType getHypervisorType(){
52435242
return hypervisorType;
52445243
}
52455244

5246-
public String mapRbdDevice(final KVMPhysicalDisk disk){
5245+
public String mapRbdDevice(final KVMPhysicalDisk disk) {
52475246
final KVMStoragePool pool = disk.getPool();
52485247
//Check if rbd image is already mapped
52495248
final String[] splitPoolImage = disk.getPath().split("/");
52505249
String device = Script.runSimpleBashScript("rbd showmapped | grep \""+splitPoolImage[0]+"[ ]*"+splitPoolImage[1]+"\" | grep -o \"[^ ]*[ ]*$\"");
5251-
if(device == null) {
5250+
if (device == null) {
52525251
//If not mapped, map and return mapped device
52535252
Script.runSimpleBashScript("rbd map " + disk.getPath() + " --id " + pool.getAuthUserName());
52545253
device = Script.runSimpleBashScript("rbd showmapped | grep \""+splitPoolImage[0]+"[ ]*"+splitPoolImage[1]+"\" | grep -o \"[^ ]*[ ]*$\"");

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

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@
4343

4444
import javax.naming.ConfigurationException;
4545

46+
import com.fasterxml.jackson.core.JsonProcessingException;
47+
import com.fasterxml.jackson.databind.JsonNode;
48+
import com.fasterxml.jackson.databind.ObjectMapper;
4649
import org.apache.cloudstack.agent.directdownload.DirectDownloadAnswer;
4750
import org.apache.cloudstack.agent.directdownload.DirectDownloadCommand;
4851
import org.apache.cloudstack.direct.download.DirectDownloadHelper;
@@ -305,7 +308,7 @@ public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) {
305308
newTemplate.setPath(primaryVol.getName());
306309
newTemplate.setSize(primaryVol.getSize());
307310

308-
if(List.of(
311+
if (List.of(
309312
StoragePoolType.RBD,
310313
StoragePoolType.PowerFlex,
311314
StoragePoolType.Linstor,
@@ -696,7 +699,7 @@ public Answer createTemplateFromVolume(final CopyCommand cmd) {
696699
templateContent += "snapshot.name=" + dateFormat.format(date) + System.getProperty("line.separator");
697700

698701

699-
try(FileOutputStream templFo = new FileOutputStream(templateProp);){
702+
try (FileOutputStream templFo = new FileOutputStream(templateProp);) {
700703
templFo.write(templateContent.getBytes());
701704
templFo.flush();
702705
} catch (final IOException e) {
@@ -761,11 +764,9 @@ private Answer createTemplateFromVolumeOrSnapshot(CopyCommand cmd) {
761764

762765
if (srcData instanceof VolumeObjectTO) {
763766
isVolume = true;
764-
}
765-
else if (srcData instanceof SnapshotObjectTO) {
767+
} else if (srcData instanceof SnapshotObjectTO) {
766768
isVolume = false;
767-
}
768-
else {
769+
} else {
769770
return new CopyCmdAnswer("unsupported object type");
770771
}
771772

@@ -831,8 +832,7 @@ else if (srcData instanceof SnapshotObjectTO) {
831832

832833
if (isVolume) {
833834
templateContent += "volume.name=" + dateFormat.format(date) + System.getProperty("line.separator");
834-
}
835-
else {
835+
} else {
836836
templateContent += "snapshot.name=" + dateFormat.format(date) + System.getProperty("line.separator");
837837
}
838838

@@ -870,8 +870,7 @@ else if (srcData instanceof SnapshotObjectTO) {
870870
} catch (Exception ex) {
871871
if (isVolume) {
872872
logger.debug("Failed to create template from volume: ", ex);
873-
}
874-
else {
873+
} else {
875874
logger.debug("Failed to create template from snapshot: ", ex);
876875
}
877876

@@ -1034,7 +1033,7 @@ public Answer backupSnapshot(final CopyCommand cmd) {
10341033
q.convert(srcFile, destFile);
10351034

10361035
final File snapFile = new File(snapshotFile);
1037-
if(snapFile.exists()) {
1036+
if (snapFile.exists()) {
10381037
size = snapFile.length();
10391038
}
10401039

@@ -1067,7 +1066,7 @@ public Answer backupSnapshot(final CopyCommand cmd) {
10671066
return new CopyCmdAnswer(result);
10681067
}
10691068
final File snapFile = new File(snapshotDestPath + "/" + descName);
1070-
if(snapFile.exists()){
1069+
if (snapFile.exists()) {
10711070
size = snapFile.length();
10721071
}
10731072
}
@@ -1406,7 +1405,7 @@ protected synchronized void attachOrDetachDisk(final Connect conn, final boolean
14061405
if (resource.getHypervisorType() == Hypervisor.HypervisorType.LXC) {
14071406
final String device = resource.mapRbdDevice(attachingDisk);
14081407
if (device != null) {
1409-
logger.debug("RBD device on host is: "+device);
1408+
logger.debug("RBD device on host is: " + device);
14101409
attachingDisk.setPath(device);
14111410
}
14121411
}
@@ -1433,11 +1432,11 @@ protected synchronized void attachOrDetachDisk(final Connect conn, final boolean
14331432
}
14341433
diskdef.setSerial(serial);
14351434
if (attachingPool.getType() == StoragePoolType.RBD) {
1436-
if(resource.getHypervisorType() == Hypervisor.HypervisorType.LXC){
1435+
if (resource.getHypervisorType() == Hypervisor.HypervisorType.LXC) {
14371436
// For LXC, map image to host and then attach to Vm
14381437
final String device = resource.mapRbdDevice(attachingDisk);
14391438
if (device != null) {
1440-
logger.debug("RBD device on host is: "+device);
1439+
logger.debug("RBD device on host is: " + device);
14411440
diskdef.defBlockBasedDisk(device, devId, busT);
14421441
} else {
14431442
throw new InternalErrorException("Error while mapping disk "+attachingDisk.getPath()+" on host");
@@ -1507,7 +1506,7 @@ protected synchronized void attachOrDetachDisk(final Connect conn, final boolean
15071506
if ((iopsWriteRateMaxLength != null) && (iopsWriteRateMaxLength > 0)) {
15081507
diskdef.setIopsWriteRateMaxLength(iopsWriteRateMaxLength);
15091508
}
1510-
if(cacheMode != null) {
1509+
if (cacheMode != null) {
15111510
diskdef.setCacheMode(DiskDef.DiskCacheMode.valueOf(cacheMode.toUpperCase()));
15121511
}
15131512

@@ -1690,7 +1689,7 @@ public Answer createVolume(final CreateObjectCommand cmd) {
16901689
}
16911690

16921691
final VolumeObjectTO newVol = new VolumeObjectTO();
1693-
if(vol != null) {
1692+
if (vol != null) {
16941693
newVol.setPath(vol.getName());
16951694
if (vol.getQemuEncryptFormat() != null) {
16961695
newVol.setEncryptFormat(vol.getQemuEncryptFormat().toString());
@@ -1793,6 +1792,7 @@ public Answer createSnapshot(final CreateObjectCommand cmd) {
17931792

17941793
String diskPath = disk.getPath();
17951794
String snapshotPath = diskPath + File.separator + snapshotName;
1795+
Long snapshotSize = null;
17961796
if (state == DomainInfo.DomainState.VIR_DOMAIN_RUNNING && !primaryPool.isExternalSnapshot()) {
17971797

17981798
validateAvailableSizeOnPoolToTakeVolumeSnapshot(primaryPool, disk);
@@ -1853,6 +1853,11 @@ public Answer createSnapshot(final CreateObjectCommand cmd) {
18531853
logger.debug("Attempting to create RBD snapshot " + disk.getName() + "@" + snapshotName);
18541854
image.snapCreate(snapshotName);
18551855

1856+
long rbdSnapshotSize = getRbdSnapshotSize(primaryPool.getSourceDir(), disk.getName(), snapshotName, primaryPool.getSourceHost(), primaryPool.getAuthUserName(), primaryPool.getAuthSecret());
1857+
if (rbdSnapshotSize > 0) {
1858+
snapshotSize = rbdSnapshotSize;
1859+
}
1860+
18561861
rbd.close(image);
18571862
r.ioCtxDestroy(io);
18581863
} catch (final Exception e) {
@@ -1876,8 +1881,11 @@ public Answer createSnapshot(final CreateObjectCommand cmd) {
18761881
}
18771882

18781883
final SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
1879-
18801884
newSnapshot.setPath(snapshotPath);
1885+
if (snapshotSize != null) {
1886+
newSnapshot.setPhysicalSize(snapshotSize);
1887+
}
1888+
18811889
return new CreateObjectAnswer(newSnapshot);
18821890
} catch (CloudRuntimeException | LibvirtException | IOException ex) {
18831891
String errorMsg = String.format("Failed take snapshot for volume [%s], in VM [%s], due to [%s].", volume, vmName, ex.getMessage());
@@ -1888,6 +1896,31 @@ public Answer createSnapshot(final CreateObjectCommand cmd) {
18881896
}
18891897
}
18901898

1899+
private long getRbdSnapshotSize(String poolPath, String diskName, String snapshotName, String rbdMonitor, String authUser, String authSecret) {
1900+
logger.debug("Get RBD snapshot size for {}/{}@{}", poolPath, diskName, snapshotName);
1901+
//cmd: rbd du <pool>/<disk-name>@<snapshot-name> --format json --mon-host <monitor-host> --id <user> --key <key> 2>/dev/null
1902+
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));
1903+
if (StringUtils.isNotBlank(snapshotDetailsInJson)) {
1904+
ObjectMapper mapper = new ObjectMapper();
1905+
try {
1906+
JsonNode root = mapper.readTree(snapshotDetailsInJson);
1907+
for (JsonNode image : root.path("images")) {
1908+
if (snapshotName.equals(image.path("snapshot").asText())) {
1909+
long usedSizeInBytes = image.path("used_size").asLong();
1910+
logger.debug("RBD snapshot {}/{}@{} used size in bytes: {}", poolPath, diskName, snapshotName, usedSizeInBytes);
1911+
return usedSizeInBytes;
1912+
}
1913+
}
1914+
} catch (JsonProcessingException e) {
1915+
logger.error("Unable to get the RBD snapshot size, RBD snapshot cmd output: {}", snapshotDetailsInJson, e);
1916+
}
1917+
} else {
1918+
logger.warn("Failed to get RBD snapshot size for {}/{}@{} - no output for RBD snapshot cmd", poolPath, diskName, snapshotName);
1919+
}
1920+
1921+
return 0;
1922+
}
1923+
18911924
protected void deleteFullVmSnapshotAfterConvertingItToExternalDiskSnapshot(Domain vm, String snapshotName, VolumeObjectTO volume, String vmName) throws LibvirtException {
18921925
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,
18931926
volume));

0 commit comments

Comments
 (0)