5555
5656import com .cloud .agent .api .Command ;
5757import 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 ;
5861import org .apache .cloudstack .agent .directdownload .DirectDownloadAnswer ;
5962import org .apache .cloudstack .agent .directdownload .DirectDownloadCommand ;
6063import org .apache .cloudstack .direct .download .DirectDownloadHelper ;
@@ -365,6 +368,16 @@ public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) {
365368 newTemplate .setPath (primaryVol .getName ());
366369 newTemplate .setSize (primaryVol .getSize ());
367370 newTemplate .setFormat (getFormat (primaryPool .getType ()));
371+
372+ if (List .of (
373+ StoragePoolType .RBD ,
374+ StoragePoolType .PowerFlex ,
375+ StoragePoolType .Linstor ,
376+ StoragePoolType .FiberChannel ).contains (primaryPool .getType ())) {
377+ newTemplate .setFormat (ImageFormat .RAW );
378+ } else {
379+ newTemplate .setFormat (ImageFormat .QCOW2 );
380+ }
368381 data = newTemplate ;
369382 } else if (destData .getObjectType () == DataObjectType .VOLUME ) {
370383 final VolumeObjectTO volumeObjectTO = new VolumeObjectTO ();
@@ -752,7 +765,7 @@ public Answer createTemplateFromVolume(final CopyCommand cmd) {
752765 templateContent += "snapshot.name=" + dateFormat .format (date ) + System .getProperty ("line.separator" );
753766
754767
755- try (FileOutputStream templFo = new FileOutputStream (templateProp );){
768+ try (FileOutputStream templFo = new FileOutputStream (templateProp );) {
756769 templFo .write (templateContent .getBytes ());
757770 templFo .flush ();
758771 } catch (final IOException e ) {
@@ -817,11 +830,9 @@ private Answer createTemplateFromVolumeOrSnapshot(CopyCommand cmd) {
817830
818831 if (srcData instanceof VolumeObjectTO ) {
819832 isVolume = true ;
820- }
821- else if (srcData instanceof SnapshotObjectTO ) {
833+ } else if (srcData instanceof SnapshotObjectTO ) {
822834 isVolume = false ;
823- }
824- else {
835+ } else {
825836 return new CopyCmdAnswer ("unsupported object type" );
826837 }
827838
@@ -887,8 +898,7 @@ else if (srcData instanceof SnapshotObjectTO) {
887898
888899 if (isVolume ) {
889900 templateContent += "volume.name=" + dateFormat .format (date ) + System .getProperty ("line.separator" );
890- }
891- else {
901+ } else {
892902 templateContent += "snapshot.name=" + dateFormat .format (date ) + System .getProperty ("line.separator" );
893903 }
894904
@@ -926,8 +936,7 @@ else if (srcData instanceof SnapshotObjectTO) {
926936 } catch (Exception ex ) {
927937 if (isVolume ) {
928938 logger .debug ("Failed to create template from volume: " , ex );
929- }
930- else {
939+ } else {
931940 logger .debug ("Failed to create template from snapshot: " , ex );
932941 }
933942
@@ -1088,7 +1097,7 @@ public Answer backupSnapshot(final CopyCommand cmd) {
10881097 q .convert (srcFile , destFile );
10891098
10901099 final File snapFile = new File (snapshotFile );
1091- if (snapFile .exists ()) {
1100+ if (snapFile .exists ()) {
10921101 size = snapFile .length ();
10931102 }
10941103
@@ -1121,7 +1130,7 @@ public Answer backupSnapshot(final CopyCommand cmd) {
11211130 return new CopyCmdAnswer (result );
11221131 }
11231132 final File snapFile = new File (snapshotDestPath + "/" + descName );
1124- if (snapFile .exists ()){
1133+ if (snapFile .exists ()) {
11251134 size = snapFile .length ();
11261135 }
11271136 }
@@ -1460,7 +1469,7 @@ protected synchronized void attachOrDetachDisk(final Connect conn, final boolean
14601469 if (resource .getHypervisorType () == Hypervisor .HypervisorType .LXC ) {
14611470 final String device = resource .mapRbdDevice (attachingDisk );
14621471 if (device != null ) {
1463- logger .debug ("RBD device on host is: " + device );
1472+ logger .debug ("RBD device on host is: " + device );
14641473 attachingDisk .setPath (device );
14651474 }
14661475 }
@@ -1487,11 +1496,11 @@ protected synchronized void attachOrDetachDisk(final Connect conn, final boolean
14871496 }
14881497 diskdef .setSerial (serial );
14891498 if (attachingPool .getType () == StoragePoolType .RBD ) {
1490- if (resource .getHypervisorType () == Hypervisor .HypervisorType .LXC ){
1499+ if (resource .getHypervisorType () == Hypervisor .HypervisorType .LXC ) {
14911500 // For LXC, map image to host and then attach to Vm
14921501 final String device = resource .mapRbdDevice (attachingDisk );
14931502 if (device != null ) {
1494- logger .debug ("RBD device on host is: " + device );
1503+ logger .debug ("RBD device on host is: " + device );
14951504 diskdef .defBlockBasedDisk (device , devId , busT );
14961505 } else {
14971506 throw new InternalErrorException ("Error while mapping disk " +attachingDisk .getPath ()+" on host" );
@@ -1561,7 +1570,7 @@ protected synchronized void attachOrDetachDisk(final Connect conn, final boolean
15611570 if ((iopsWriteRateMaxLength != null ) && (iopsWriteRateMaxLength > 0 )) {
15621571 diskdef .setIopsWriteRateMaxLength (iopsWriteRateMaxLength );
15631572 }
1564- if (cacheMode != null ) {
1573+ if (cacheMode != null ) {
15651574 diskdef .setCacheMode (DiskDef .DiskCacheMode .valueOf (cacheMode .toUpperCase ()));
15661575 }
15671576
@@ -1748,7 +1757,7 @@ public Answer createVolume(final CreateObjectCommand cmd) {
17481757 }
17491758
17501759 final VolumeObjectTO newVol = new VolumeObjectTO ();
1751- if (vol != null ) {
1760+ if (vol != null ) {
17521761 newVol .setPath (vol .getName ());
17531762 if (vol .getQemuEncryptFormat () != null ) {
17541763 newVol .setEncryptFormat (vol .getQemuEncryptFormat ().toString ());
@@ -1853,8 +1862,11 @@ public Answer createSnapshot(final CreateObjectCommand cmd) {
18531862 }
18541863 } else {
18551864 if (primaryPool .getType () == StoragePoolType .RBD ) {
1856- takeRbdVolumeSnapshotOfStoppedVm (primaryPool , disk , snapshotName );
1865+ Long snapshotSize = takeRbdVolumeSnapshotOfStoppedVm (primaryPool , disk , snapshotName );
18571866 newSnapshot .setPath (snapshotPath );
1867+ if (snapshotSize != null ) {
1868+ newSnapshot .setPhysicalSize (snapshotSize );
1869+ }
18581870 } else if (primaryPool .getType () == StoragePoolType .CLVM ) {
18591871 CreateObjectAnswer result = takeClvmVolumeSnapshotOfStoppedVm (disk , snapshotName );
18601872 if (result != null ) return result ;
@@ -2306,7 +2318,8 @@ private CreateObjectAnswer takeClvmVolumeSnapshotOfStoppedVm(KVMPhysicalDisk dis
23062318 * barriers properly (>2.6.32) this won't be any different then pulling the power
23072319 * cord out of a running machine.
23082320 */
2309- private void takeRbdVolumeSnapshotOfStoppedVm (KVMStoragePool primaryPool , KVMPhysicalDisk disk , String snapshotName ) {
2321+ private Long takeRbdVolumeSnapshotOfStoppedVm (KVMStoragePool primaryPool , KVMPhysicalDisk disk , String snapshotName ) {
2322+ Long snapshotSize = null ;
23102323 try {
23112324 Rados r = radosConnect (primaryPool );
23122325
@@ -2317,11 +2330,43 @@ private void takeRbdVolumeSnapshotOfStoppedVm(KVMStoragePool primaryPool, KVMPhy
23172330 logger .debug ("Attempting to create RBD snapshot {}@{}" , disk .getName (), snapshotName );
23182331 image .snapCreate (snapshotName );
23192332
2333+ image .snapCreate (snapshotName );
2334+ long rbdSnapshotSize = getRbdSnapshotSize (primaryPool .getSourceDir (), disk .getName (), snapshotName , primaryPool .getSourceHost (), primaryPool .getAuthUserName (), primaryPool .getAuthSecret ());
2335+ if (rbdSnapshotSize > 0 ) {
2336+ snapshotSize = rbdSnapshotSize ;
2337+ }
2338+
23202339 rbd .close (image );
23212340 r .ioCtxDestroy (io );
23222341 } catch (final Exception e ) {
23232342 logger .error ("A RBD snapshot operation on [{}] failed. The error was: {}" , disk .getName (), e .getMessage (), e );
23242343 }
2344+ return snapshotSize ;
2345+ }
2346+
2347+ private long getRbdSnapshotSize (String poolPath , String diskName , String snapshotName , String rbdMonitor , String authUser , String authSecret ) {
2348+ logger .debug ("Get RBD snapshot size for {}/{}@{}" , poolPath , diskName , snapshotName );
2349+ //cmd: rbd du <pool>/<disk-name>@<snapshot-name> --format json --mon-host <monitor-host> --id <user> --key <key> 2>/dev/null
2350+ 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 ));
2351+ if (StringUtils .isNotBlank (snapshotDetailsInJson )) {
2352+ ObjectMapper mapper = new ObjectMapper ();
2353+ try {
2354+ JsonNode root = mapper .readTree (snapshotDetailsInJson );
2355+ for (JsonNode image : root .path ("images" )) {
2356+ if (snapshotName .equals (image .path ("snapshot" ).asText ())) {
2357+ long usedSizeInBytes = image .path ("used_size" ).asLong ();
2358+ logger .debug ("RBD snapshot {}/{}@{} used size in bytes: {}" , poolPath , diskName , snapshotName , usedSizeInBytes );
2359+ return usedSizeInBytes ;
2360+ }
2361+ }
2362+ } catch (JsonProcessingException e ) {
2363+ logger .error ("Unable to get the RBD snapshot size, RBD snapshot cmd output: {}" , snapshotDetailsInJson , e );
2364+ }
2365+ } else {
2366+ logger .warn ("Failed to get RBD snapshot size for {}/{}@{} - no output for RBD snapshot cmd" , poolPath , diskName , snapshotName );
2367+ }
2368+
2369+ return 0 ;
23252370 }
23262371
23272372 /**
0 commit comments