4343
4444import 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 ;
4649import org .apache .cloudstack .agent .directdownload .DirectDownloadAnswer ;
4750import org .apache .cloudstack .agent .directdownload .DirectDownloadCommand ;
4851import 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