2727import com .cloud .storage .Storage ;
2828import com .cloud .storage .StoragePool ;
2929import com .cloud .storage .Volume ;
30+ import com .cloud .storage .VolumeVO ;
31+ import com .cloud .storage .dao .SnapshotDetailsDao ;
32+ import com .cloud .storage .dao .SnapshotDetailsVO ;
33+ import com .cloud .storage .dao .VolumeDao ;
34+ import com .cloud .storage .dao .VolumeDetailsDao ;
3035import com .cloud .utils .Pair ;
3136import com .cloud .utils .exception .CloudRuntimeException ;
3237import org .apache .cloudstack .engine .subsystem .api .storage .ChapInfo ;
4146import org .apache .cloudstack .engine .subsystem .api .storage .VolumeInfo ;
4247import org .apache .cloudstack .framework .async .AsyncCompletionCallback ;
4348import org .apache .cloudstack .storage .command .CommandResult ;
49+ import org .apache .cloudstack .storage .command .CreateObjectAnswer ;
4450import org .apache .cloudstack .storage .datastore .db .PrimaryDataStoreDao ;
4551import org .apache .cloudstack .storage .datastore .db .StoragePoolDetailsDao ;
4652import org .apache .cloudstack .storage .datastore .db .StoragePoolVO ;
53+ import org .apache .cloudstack .storage .feign .model .FileInfo ;
4754import org .apache .cloudstack .storage .service .StorageStrategy ;
4855import org .apache .cloudstack .storage .service .model .CloudStackVolume ;
4956import org .apache .cloudstack .storage .service .model .ProtocolType ;
57+ import org .apache .cloudstack .storage .to .SnapshotObjectTO ;
5058import org .apache .cloudstack .storage .utils .Constants ;
5159import org .apache .cloudstack .storage .utils .Utility ;
60+ import org .apache .commons .lang3 .StringUtils ;
5261import org .apache .logging .log4j .LogManager ;
5362import org .apache .logging .log4j .Logger ;
5463
@@ -62,6 +71,9 @@ public class OntapPrimaryDatastoreDriver implements PrimaryDataStoreDriver {
6271
6372 @ Inject private StoragePoolDetailsDao storagePoolDetailsDao ;
6473 @ Inject private PrimaryDataStoreDao storagePoolDao ;
74+ @ Inject private VolumeDao volumeDao ;
75+ @ Inject private VolumeDetailsDao volumeDetailsDao ;
76+ @ Inject private SnapshotDetailsDao snapshotDetailsDao ;
6577
6678 @ Override
6779 public Map <String , String > getCapabilities () {
@@ -227,6 +239,79 @@ public long getUsedIops(StoragePool storagePool) {
227239 @ Override
228240 public void takeSnapshot (SnapshotInfo snapshot , AsyncCompletionCallback <CreateCmdResult > callback ) {
229241
242+ CreateCmdResult result ;
243+
244+ try {
245+ VolumeInfo volumeInfo = snapshot .getBaseVolume ();
246+
247+ VolumeVO volumeVO = volumeDao .findById (volumeInfo .getId ());
248+ if (volumeVO == null ) {
249+ throw new CloudRuntimeException ("takeSnapshot: VolumeVO not found for id: " + volumeInfo .getId ());
250+ }
251+
252+ /** we are keeping file path at volumeVO.getPath() */
253+
254+ StoragePoolVO storagePool = storagePoolDao .findById (volumeVO .getPoolId ());
255+ if (storagePool == null ) {
256+ s_logger .error ("takeSnapshot : Storage Pool not found for id: " + volumeVO .getPoolId ());
257+ throw new CloudRuntimeException ("takeSnapshot : Storage Pool not found for id: " + volumeVO .getPoolId ());
258+ }
259+ Map <String , String > poolDetails = storagePoolDetailsDao .listDetailsKeyPairs (volumeVO .getPoolId ());
260+ StorageStrategy storageStrategy = Utility .getStrategyByStoragePoolDetails (poolDetails );
261+
262+ CloudStackVolume cloudStackVolumeRequest = getCloudStackVolumeRequestByProtocol (poolDetails , volumeVO .getPath ());
263+ CloudStackVolume cloudStackVolume = storageStrategy .getCloudStackVolume (cloudStackVolumeRequest );
264+ if (cloudStackVolume == null || cloudStackVolume .getFile () == null ) {
265+ throw new CloudRuntimeException ("takeSnapshot: Failed to get source file to take snapshot" );
266+ }
267+ long capacityBytes = storagePool .getCapacityBytes ();
268+
269+ long usedBytes = getUsedBytes (storagePool );
270+ long fileSize = cloudStackVolume .getFile ().getSize ();
271+
272+ usedBytes += fileSize ;
273+
274+ if (usedBytes > capacityBytes ) {
275+ throw new CloudRuntimeException ("Insufficient space remains in this primary storage to take a snapshot" );
276+ }
277+
278+ storagePool .setUsedBytes (usedBytes );
279+
280+ SnapshotObjectTO snapshotObjectTo = (SnapshotObjectTO )snapshot .getTO ();
281+
282+ String fileSnapshotName = volumeInfo .getName () + "-" + snapshot .getUuid ();
283+
284+ int maxSnapshotNameLength = 64 ;
285+ int trimRequired = fileSnapshotName .length () - maxSnapshotNameLength ;
286+
287+ if (trimRequired > 0 ) {
288+ fileSnapshotName = StringUtils .left (volumeInfo .getName (), (volumeInfo .getName ().length () - trimRequired )) + "-" + snapshot .getUuid ();
289+ }
290+
291+ CloudStackVolume snapCloudStackVolumeRequest = snapshotCloudStackVolumeRequestByProtocol (poolDetails , volumeVO .getPath (), fileSnapshotName );
292+ CloudStackVolume cloneCloudStackVolume = storageStrategy .snapshotCloudStackVolume (snapCloudStackVolumeRequest );
293+
294+ updateSnapshotDetails (snapshot .getId (), volumeInfo .getId (), poolDetails .get (Constants .VOLUME_UUID ), cloneCloudStackVolume .getFile ().getPath (), volumeVO .getPoolId (), fileSize );
295+
296+ snapshotObjectTo .setPath (Constants .ONTAP_SNAP_ID +"=" +cloneCloudStackVolume .getFile ().getPath ());
297+
298+ /** Update size for the storage-pool including snapshot size */
299+ storagePoolDao .update (volumeVO .getPoolId (), storagePool );
300+
301+ CreateObjectAnswer createObjectAnswer = new CreateObjectAnswer (snapshotObjectTo );
302+
303+ result = new CreateCmdResult (null , createObjectAnswer );
304+
305+ result .setResult (null );
306+ }
307+ catch (Exception ex ) {
308+ s_logger .error ("takeSnapshot: Failed due to " , ex );
309+ result = new CreateCmdResult (null , new CreateObjectAnswer (ex .toString ()));
310+
311+ result .setResult (ex .toString ());
312+ }
313+
314+ callback .complete (result );
230315 }
231316
232317 @ Override
@@ -293,4 +378,87 @@ public boolean isStorageSupportHA(Storage.StoragePoolType type) {
293378 public void detachVolumeFromAllStorageNodes (Volume volume ) {
294379
295380 }
381+
382+
383+ private CloudStackVolume getCloudStackVolumeRequestByProtocol (Map <String , String > details , String filePath ) {
384+ CloudStackVolume cloudStackVolumeRequest = null ;
385+ ProtocolType protocolType = null ;
386+ String protocol = null ;
387+
388+ try {
389+ protocol = details .get (Constants .PROTOCOL );
390+ protocolType = ProtocolType .valueOf (protocol );
391+ } catch (IllegalArgumentException e ) {
392+ throw new CloudRuntimeException ("getCloudStackVolumeRequestByProtocol: Protocol: " + protocol +" is not valid" );
393+ }
394+ switch (protocolType ) {
395+ case NFS3 :
396+ cloudStackVolumeRequest = new CloudStackVolume ();
397+ FileInfo fileInfo = new FileInfo ();
398+ fileInfo .setPath (filePath );
399+ cloudStackVolumeRequest .setFile (fileInfo );
400+ String volumeUuid = details .get (Constants .VOLUME_UUID );
401+ cloudStackVolumeRequest .setFlexVolumeUuid (volumeUuid );
402+ break ;
403+ default :
404+ throw new CloudRuntimeException ("createCloudStackVolumeRequestByProtocol: Unsupported protocol " + protocol );
405+ }
406+ return cloudStackVolumeRequest ;
407+ }
408+
409+ private CloudStackVolume snapshotCloudStackVolumeRequestByProtocol (Map <String , String > details ,
410+ String sourcePath ,
411+ String destinationPath ) {
412+ CloudStackVolume cloudStackVolumeRequest = null ;
413+ ProtocolType protocolType = null ;
414+ String protocol = null ;
415+
416+ try {
417+ protocol = details .get (Constants .PROTOCOL );
418+ protocolType = ProtocolType .valueOf (protocol );
419+ } catch (IllegalArgumentException e ) {
420+ throw new CloudRuntimeException ("getCloudStackVolumeRequestByProtocol: Protocol: " + protocol +" is not valid" );
421+ }
422+ switch (protocolType ) {
423+ case NFS3 :
424+ cloudStackVolumeRequest = new CloudStackVolume ();
425+ FileInfo fileInfo = new FileInfo ();
426+ fileInfo .setPath (sourcePath );
427+ cloudStackVolumeRequest .setFile (fileInfo );
428+ String volumeUuid = details .get (Constants .VOLUME_UUID );
429+ cloudStackVolumeRequest .setFlexVolumeUuid (volumeUuid );
430+ cloudStackVolumeRequest .setDestinationPath (destinationPath );
431+ break ;
432+ default :
433+ throw new CloudRuntimeException ("createCloudStackVolumeRequestByProtocol: Unsupported protocol " + protocol );
434+
435+ }
436+ return cloudStackVolumeRequest ;
437+ }
438+
439+ /**
440+ *
441+ * @param csSnapshotId: generated snapshot id from cloudstack
442+ * @param csVolumeId: Source CS volume id
443+ * @param ontapVolumeUuid: storage flexvolume id
444+ * @param ontapNewSnapshot: generated snapshot id from ONTAP
445+ * @param storagePoolId: primary storage pool id
446+ * @param ontapSnapSize: Size of snapshot CS volume(LUN/file)
447+ */
448+ private void updateSnapshotDetails (long csSnapshotId , long csVolumeId , String ontapVolumeUuid , String ontapNewSnapshot , long storagePoolId , long ontapSnapSize ) {
449+ SnapshotDetailsVO snapshotDetail = new SnapshotDetailsVO (csSnapshotId , Constants .SRC_CS_VOLUME_ID , String .valueOf (csVolumeId ), false );
450+ snapshotDetailsDao .persist (snapshotDetail );
451+
452+ snapshotDetail = new SnapshotDetailsVO (csSnapshotId , Constants .BASE_ONTAP_FV_ID , String .valueOf (ontapVolumeUuid ), false );
453+ snapshotDetailsDao .persist (snapshotDetail );
454+
455+ snapshotDetail = new SnapshotDetailsVO (csSnapshotId , Constants .ONTAP_SNAP_ID , String .valueOf (ontapNewSnapshot ), false );
456+ snapshotDetailsDao .persist (snapshotDetail );
457+
458+ snapshotDetail = new SnapshotDetailsVO (csSnapshotId , Constants .PRIMARY_POOL_ID , String .valueOf (storagePoolId ), false );
459+ snapshotDetailsDao .persist (snapshotDetail );
460+
461+ snapshotDetail = new SnapshotDetailsVO (csSnapshotId , Constants .ONTAP_SNAP_SIZE , String .valueOf (ontapSnapSize ), false );
462+ snapshotDetailsDao .persist (snapshotDetail );
463+ }
296464}
0 commit comments