3131import com .cloud .resource .ResourceWrapper ;
3232import com .cloud .storage .Storage ;
3333import com .cloud .utils .exception .CloudRuntimeException ;
34+ import org .apache .cloudstack .storage .volume .VolumeOnStorageTO ;
3435import org .apache .cloudstack .utils .qemu .QemuImg ;
3536import org .apache .cloudstack .utils .qemu .QemuImgException ;
3637import org .apache .cloudstack .utils .qemu .QemuImgFile ;
38+ import org .apache .commons .collections .MapUtils ;
39+ import org .apache .commons .lang3 .StringUtils ;
3740import org .apache .log4j .Logger ;
3841import org .libvirt .LibvirtException ;
3942
43+ import java .util .Arrays ;
44+ import java .util .HashMap ;
45+ import java .util .List ;
4046import java .util .Map ;
4147
4248@ ResourceWrapper (handles = CopyRemoteVolumeCommand .class )
4349public final class LibvirtCopyRemoteVolumeCommandWrapper extends CommandWrapper <CopyRemoteVolumeCommand , Answer , LibvirtComputingResource > {
4450
4551 private static final Logger s_logger = Logger .getLogger (LibvirtCopyRemoteVolumeCommandWrapper .class );
52+ private static final List <Storage .StoragePoolType > STORAGE_POOL_TYPES_SUPPORTED = Arrays .asList (Storage .StoragePoolType .Filesystem , Storage .StoragePoolType .NetworkFilesystem );
4653
4754 @ Override
4855 public Answer execute (final CopyRemoteVolumeCommand command , final LibvirtComputingResource libvirtComputingResource ) {
@@ -58,14 +65,19 @@ public Answer execute(final CopyRemoteVolumeCommand command, final LibvirtComput
5865 int timeoutInSecs = command .getWait ();
5966
6067 try {
61- if (storageFilerTO .getType () == Storage .StoragePoolType .Filesystem ||
62- storageFilerTO .getType () == Storage .StoragePoolType .NetworkFilesystem ) {
68+ if (STORAGE_POOL_TYPES_SUPPORTED .contains (storageFilerTO .getType ())) {
6369 String filename = libvirtComputingResource .copyVolume (srcIp , username , password , dstPath , srcFile , tmpPath , timeoutInSecs );
6470 s_logger .debug ("Volume " + srcFile + " copy successful, copied to file: " + filename );
6571 final KVMPhysicalDisk vol = pool .getPhysicalDisk (filename );
6672 final String path = vol .getPath ();
67- long size = getVirtualSizeFromFile (path );
68- return new CopyRemoteVolumeAnswer (command , "" , filename , size );
73+ try {
74+ KVMPhysicalDisk .checkQcow2File (path );
75+ } catch (final CloudRuntimeException e ) {
76+ return new CopyRemoteVolumeAnswer (command , false , "" , filename , 0 , getVolumeDetails (pool , vol ));
77+ }
78+
79+ long size = KVMPhysicalDisk .getVirtualSizeFromFile (path );
80+ return new CopyRemoteVolumeAnswer (command , true , "" , filename , size , getVolumeDetails (pool , vol ));
6981 } else {
7082 String msg = "Unsupported storage pool type: " + storageFilerTO .getType ().toString () + ", only local and NFS pools are supported" ;
7183 return new Answer (command , false , msg );
@@ -77,18 +89,56 @@ public Answer execute(final CopyRemoteVolumeCommand command, final LibvirtComput
7789 }
7890 }
7991
80- private long getVirtualSizeFromFile (String path ) {
92+ private Map <VolumeOnStorageTO .Detail , String > getVolumeDetails (KVMStoragePool pool , KVMPhysicalDisk disk ) {
93+ Map <String , String > info = getDiskFileInfo (pool , disk , true );
94+ if (MapUtils .isEmpty (info )) {
95+ return null ;
96+ }
97+
98+ Map <VolumeOnStorageTO .Detail , String > volumeDetails = new HashMap <>();
99+
100+ String backingFilePath = info .get (QemuImg .BACKING_FILE );
101+ if (StringUtils .isNotBlank (backingFilePath )) {
102+ volumeDetails .put (VolumeOnStorageTO .Detail .BACKING_FILE , backingFilePath );
103+ }
104+ String backingFileFormat = info .get (QemuImg .BACKING_FILE_FORMAT );
105+ if (StringUtils .isNotBlank (backingFileFormat )) {
106+ volumeDetails .put (VolumeOnStorageTO .Detail .BACKING_FILE_FORMAT , backingFileFormat );
107+ }
108+ String clusterSize = info .get (QemuImg .CLUSTER_SIZE );
109+ if (StringUtils .isNotBlank (clusterSize )) {
110+ volumeDetails .put (VolumeOnStorageTO .Detail .CLUSTER_SIZE , clusterSize );
111+ }
112+ String fileFormat = info .get (QemuImg .FILE_FORMAT );
113+ if (StringUtils .isNotBlank (fileFormat )) {
114+ volumeDetails .put (VolumeOnStorageTO .Detail .FILE_FORMAT , fileFormat );
115+ }
116+ String encrypted = info .get (QemuImg .ENCRYPTED );
117+ if (StringUtils .isNotBlank (encrypted ) && encrypted .equalsIgnoreCase ("yes" )) {
118+ volumeDetails .put (VolumeOnStorageTO .Detail .IS_ENCRYPTED , String .valueOf (Boolean .TRUE ));
119+ }
120+ Boolean isLocked = isDiskFileLocked (pool , disk );
121+ volumeDetails .put (VolumeOnStorageTO .Detail .IS_LOCKED , String .valueOf (isLocked ));
122+
123+ return volumeDetails ;
124+ }
125+
126+ private Map <String , String > getDiskFileInfo (KVMStoragePool pool , KVMPhysicalDisk disk , boolean secure ) {
127+ if (!STORAGE_POOL_TYPES_SUPPORTED .contains (pool .getType ())) {
128+ return new HashMap <>(); // unknown
129+ }
81130 try {
82131 QemuImg qemu = new QemuImg (0 );
83- QemuImgFile qemuFile = new QemuImgFile (path );
84- Map <String , String > info = qemu .info (qemuFile );
85- if (info .containsKey (QemuImg .VIRTUAL_SIZE )) {
86- return Long .parseLong (info .get (QemuImg .VIRTUAL_SIZE ));
87- } else {
88- throw new CloudRuntimeException ("Unable to determine virtual size of volume at path " + path );
89- }
132+ QemuImgFile qemuFile = new QemuImgFile (disk .getPath (), disk .getFormat ());
133+ return qemu .info (qemuFile , secure );
90134 } catch (QemuImgException | LibvirtException ex ) {
91- throw new CloudRuntimeException ("Error when inspecting volume at path " + path , ex );
135+ logger .error ("Failed to get info of disk file: " + ex .getMessage ());
136+ return null ;
92137 }
93138 }
139+
140+ private boolean isDiskFileLocked (KVMStoragePool pool , KVMPhysicalDisk disk ) {
141+ Map <String , String > info = getDiskFileInfo (pool , disk , false );
142+ return info == null ;
143+ }
94144}
0 commit comments