2929import com .cloud .storage .Volume ;
3030import com .cloud .storage .VolumeVO ;
3131import com .cloud .storage .ScopeType ;
32+ import com .cloud .storage .dao .SnapshotDetailsDao ;
33+ import com .cloud .storage .dao .SnapshotDetailsVO ;
3234import com .cloud .storage .dao .VolumeDao ;
3335import com .cloud .storage .dao .VolumeDetailsDao ;
3436import com .cloud .utils .Pair ;
4749import org .apache .cloudstack .engine .subsystem .api .storage .VolumeInfo ;
4850import org .apache .cloudstack .framework .async .AsyncCompletionCallback ;
4951import org .apache .cloudstack .storage .command .CommandResult ;
52+ import org .apache .cloudstack .storage .command .CreateObjectAnswer ;
5053import org .apache .cloudstack .storage .datastore .db .PrimaryDataStoreDao ;
5154import org .apache .cloudstack .storage .datastore .db .StoragePoolDetailsDao ;
5255import org .apache .cloudstack .storage .datastore .db .StoragePoolVO ;
56+ import org .apache .cloudstack .storage .feign .model .FileInfo ;
5357import org .apache .cloudstack .storage .feign .model .Lun ;
5458import org .apache .cloudstack .storage .service .SANStrategy ;
5559import org .apache .cloudstack .storage .service .StorageStrategy ;
5660import org .apache .cloudstack .storage .service .UnifiedSANStrategy ;
5761import org .apache .cloudstack .storage .service .model .AccessGroup ;
5862import org .apache .cloudstack .storage .service .model .CloudStackVolume ;
5963import org .apache .cloudstack .storage .service .model .ProtocolType ;
64+ import org .apache .cloudstack .storage .to .SnapshotObjectTO ;
6065import org .apache .cloudstack .storage .utils .Constants ;
6166import org .apache .cloudstack .storage .utils .Utility ;
67+ import org .apache .commons .lang3 .StringUtils ;
6268import org .apache .logging .log4j .LogManager ;
6369import org .apache .logging .log4j .Logger ;
6470
@@ -80,14 +86,16 @@ public class OntapPrimaryDatastoreDriver implements PrimaryDataStoreDriver {
8086 @ Inject private VMInstanceDao vmDao ;
8187 @ Inject private VolumeDao volumeDao ;
8288 @ Inject private VolumeDetailsDao volumeDetailsDao ;
89+ @ Inject private SnapshotDetailsDao snapshotDetailsDao ;
90+
8391 @ Override
8492 public Map <String , String > getCapabilities () {
8593 s_logger .trace ("OntapPrimaryDatastoreDriver: getCapabilities: Called" );
8694 Map <String , String > mapCapabilities = new HashMap <>();
8795 // RAW managed initial implementation: snapshot features not yet supported
8896 // TODO Set it to false once we start supporting snapshot feature
89- mapCapabilities .put (DataStoreCapabilities .STORAGE_SYSTEM_SNAPSHOT .toString (), Boolean .FALSE .toString ());
90- mapCapabilities .put (DataStoreCapabilities .CAN_CREATE_VOLUME_FROM_SNAPSHOT .toString (), Boolean .FALSE .toString ());
97+ mapCapabilities .put (DataStoreCapabilities .STORAGE_SYSTEM_SNAPSHOT .toString (), Boolean .TRUE .toString ());
98+ mapCapabilities .put (DataStoreCapabilities .CAN_CREATE_VOLUME_FROM_SNAPSHOT .toString (), Boolean .TRUE .toString ());
9199 return mapCapabilities ;
92100 }
93101
@@ -525,6 +533,81 @@ public long getUsedIops(StoragePool storagePool) {
525533 @ Override
526534 public void takeSnapshot (SnapshotInfo snapshot , AsyncCompletionCallback <CreateCmdResult > callback ) {
527535
536+ CreateCmdResult result ;
537+
538+ try {
539+ VolumeInfo volumeInfo = snapshot .getBaseVolume ();
540+
541+ VolumeVO volumeVO = volumeDao .findById (volumeInfo .getId ());
542+ if (volumeVO == null ) {
543+ throw new CloudRuntimeException ("takeSnapshot: VolumeVO not found for id: " + volumeInfo .getId ());
544+ }
545+
546+ /** we are keeping file path at volumeVO.getPath() */
547+
548+ StoragePoolVO storagePool = storagePoolDao .findById (volumeVO .getPoolId ());
549+ if (storagePool == null ) {
550+ s_logger .error ("takeSnapshot : Storage Pool not found for id: " + volumeVO .getPoolId ());
551+ throw new CloudRuntimeException ("takeSnapshot : Storage Pool not found for id: " + volumeVO .getPoolId ());
552+ }
553+ Map <String , String > poolDetails = storagePoolDetailsDao .listDetailsKeyPairs (volumeVO .getPoolId ());
554+ StorageStrategy storageStrategy = Utility .getStrategyByStoragePoolDetails (poolDetails );
555+
556+ Map <String , String > cloudStackVolumeRequestMap = new HashMap <>();
557+ cloudStackVolumeRequestMap .put (Constants .VOLUME_UUID , poolDetails .get (Constants .VOLUME_UUID ));
558+ cloudStackVolumeRequestMap .put (Constants .FILE_PATH , volumeVO .getPath ());
559+ CloudStackVolume cloudStackVolume = storageStrategy .getCloudStackVolume (cloudStackVolumeRequestMap );
560+ if (cloudStackVolume == null || cloudStackVolume .getFile () == null ) {
561+ throw new CloudRuntimeException ("takeSnapshot: Failed to get source file to take snapshot" );
562+ }
563+ long capacityBytes = storagePool .getCapacityBytes ();
564+
565+ long usedBytes = getUsedBytes (storagePool );
566+ long fileSize = cloudStackVolume .getFile ().getSize ();
567+
568+ usedBytes += fileSize ;
569+
570+ if (usedBytes > capacityBytes ) {
571+ throw new CloudRuntimeException ("Insufficient space remains in this primary storage to take a snapshot" );
572+ }
573+
574+ storagePool .setUsedBytes (usedBytes );
575+
576+ SnapshotObjectTO snapshotObjectTo = (SnapshotObjectTO )snapshot .getTO ();
577+
578+ String fileSnapshotName = volumeInfo .getName () + "-" + snapshot .getUuid ();
579+
580+ int maxSnapshotNameLength = 64 ;
581+ int trimRequired = fileSnapshotName .length () - maxSnapshotNameLength ;
582+
583+ if (trimRequired > 0 ) {
584+ fileSnapshotName = StringUtils .left (volumeInfo .getName (), (volumeInfo .getName ().length () - trimRequired )) + "-" + snapshot .getUuid ();
585+ }
586+
587+ CloudStackVolume snapCloudStackVolumeRequest = snapshotCloudStackVolumeRequestByProtocol (poolDetails , volumeVO .getPath (), fileSnapshotName );
588+ CloudStackVolume cloneCloudStackVolume = storageStrategy .snapshotCloudStackVolume (snapCloudStackVolumeRequest );
589+
590+ updateSnapshotDetails (snapshot .getId (), volumeInfo .getId (), poolDetails .get (Constants .VOLUME_UUID ), cloneCloudStackVolume .getFile ().getPath (), volumeVO .getPoolId (), fileSize );
591+
592+ snapshotObjectTo .setPath (Constants .ONTAP_SNAP_ID +"=" +cloneCloudStackVolume .getFile ().getPath ());
593+
594+ /** Update size for the storage-pool including snapshot size */
595+ storagePoolDao .update (volumeVO .getPoolId (), storagePool );
596+
597+ CreateObjectAnswer createObjectAnswer = new CreateObjectAnswer (snapshotObjectTo );
598+
599+ result = new CreateCmdResult (null , createObjectAnswer );
600+
601+ result .setResult (null );
602+ }
603+ catch (Exception ex ) {
604+ s_logger .error ("takeSnapshot: Failed due to " , ex );
605+ result = new CreateCmdResult (null , new CreateObjectAnswer (ex .toString ()));
606+
607+ result .setResult (ex .toString ());
608+ }
609+
610+ callback .complete (result );
528611 }
529612
530613 @ Override
@@ -622,4 +705,87 @@ private CloudStackVolume createDeleteCloudStackVolumeRequest(StoragePool storage
622705 return cloudStackVolumeDeleteRequest ;
623706
624707 }
708+
709+ private CloudStackVolume getCloudStackVolumeRequestByProtocol (Map <String , String > details , String filePath ) {
710+ CloudStackVolume cloudStackVolumeRequest = null ;
711+ ProtocolType protocolType = null ;
712+ String protocol = null ;
713+
714+ try {
715+ protocol = details .get (Constants .PROTOCOL );
716+ protocolType = ProtocolType .valueOf (protocol );
717+ } catch (IllegalArgumentException e ) {
718+ throw new CloudRuntimeException ("getCloudStackVolumeRequestByProtocol: Protocol: " + protocol +" is not valid" );
719+ }
720+ switch (protocolType ) {
721+ case NFS3 :
722+ cloudStackVolumeRequest = new CloudStackVolume ();
723+ FileInfo fileInfo = new FileInfo ();
724+ fileInfo .setPath (filePath );
725+ cloudStackVolumeRequest .setFile (fileInfo );
726+ String volumeUuid = details .get (Constants .VOLUME_UUID );
727+ cloudStackVolumeRequest .setFlexVolumeUuid (volumeUuid );
728+ break ;
729+ default :
730+ throw new CloudRuntimeException ("createCloudStackVolumeRequestByProtocol: Unsupported protocol " + protocol );
731+ }
732+ return cloudStackVolumeRequest ;
733+ }
734+
735+ private CloudStackVolume snapshotCloudStackVolumeRequestByProtocol (Map <String , String > details ,
736+ String sourcePath ,
737+ String destinationPath ) {
738+ CloudStackVolume cloudStackVolumeRequest = null ;
739+ ProtocolType protocolType = null ;
740+ String protocol = null ;
741+
742+ try {
743+ protocol = details .get (Constants .PROTOCOL );
744+ protocolType = ProtocolType .valueOf (protocol );
745+ } catch (IllegalArgumentException e ) {
746+ throw new CloudRuntimeException ("getCloudStackVolumeRequestByProtocol: Protocol: " + protocol +" is not valid" );
747+ }
748+ switch (protocolType ) {
749+ case NFS3 :
750+ cloudStackVolumeRequest = new CloudStackVolume ();
751+ FileInfo fileInfo = new FileInfo ();
752+ fileInfo .setPath (sourcePath );
753+ cloudStackVolumeRequest .setFile (fileInfo );
754+ String volumeUuid = details .get (Constants .VOLUME_UUID );
755+ cloudStackVolumeRequest .setFlexVolumeUuid (volumeUuid );
756+ cloudStackVolumeRequest .setDestinationPath (destinationPath );
757+ break ;
758+ default :
759+ throw new CloudRuntimeException ("createCloudStackVolumeRequestByProtocol: Unsupported protocol " + protocol );
760+
761+ }
762+ return cloudStackVolumeRequest ;
763+ }
764+
765+ /**
766+ *
767+ * @param csSnapshotId: generated snapshot id from cloudstack
768+ * @param csVolumeId: Source CS volume id
769+ * @param ontapVolumeUuid: storage flexvolume id
770+ * @param ontapNewSnapshot: generated snapshot id from ONTAP
771+ * @param storagePoolId: primary storage pool id
772+ * @param ontapSnapSize: Size of snapshot CS volume(LUN/file)
773+ */
774+ private void updateSnapshotDetails (long csSnapshotId , long csVolumeId , String ontapVolumeUuid , String ontapNewSnapshot , long storagePoolId , long ontapSnapSize ) {
775+ SnapshotDetailsVO snapshotDetail = new SnapshotDetailsVO (csSnapshotId , Constants .SRC_CS_VOLUME_ID , String .valueOf (csVolumeId ), false );
776+ snapshotDetailsDao .persist (snapshotDetail );
777+
778+ snapshotDetail = new SnapshotDetailsVO (csSnapshotId , Constants .BASE_ONTAP_FV_ID , String .valueOf (ontapVolumeUuid ), false );
779+ snapshotDetailsDao .persist (snapshotDetail );
780+
781+ snapshotDetail = new SnapshotDetailsVO (csSnapshotId , Constants .ONTAP_SNAP_ID , String .valueOf (ontapNewSnapshot ), false );
782+ snapshotDetailsDao .persist (snapshotDetail );
783+
784+ snapshotDetail = new SnapshotDetailsVO (csSnapshotId , Constants .PRIMARY_POOL_ID , String .valueOf (storagePoolId ), false );
785+ snapshotDetailsDao .persist (snapshotDetail );
786+
787+ snapshotDetail = new SnapshotDetailsVO (csSnapshotId , Constants .ONTAP_SNAP_SIZE , String .valueOf (ontapSnapSize ), false );
788+ snapshotDetailsDao .persist (snapshotDetail );
789+ }
790+
625791}
0 commit comments