3131import com .cloud .storage .ScopeType ;
3232import com .cloud .storage .dao .VolumeDao ;
3333import com .cloud .storage .dao .VolumeDetailsDao ;
34+ import com .cloud .storage .dao .SnapshotDetailsDao ;
35+ import com .cloud .storage .dao .SnapshotDetailsVO ;
3436import com .cloud .utils .Pair ;
3537import com .cloud .utils .exception .CloudRuntimeException ;
3638import com .cloud .vm .VirtualMachine ;
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 ;
5356import org .apache .cloudstack .storage .feign .model .Lun ;
5457import org .apache .cloudstack .storage .service .SANStrategy ;
58+ import org .apache .cloudstack .storage .feign .model .FileInfo ;
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,6 +86,8 @@ 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" );
@@ -88,6 +96,7 @@ public Map<String, String> getCapabilities() {
8896 // TODO Set it to false once we start supporting snapshot feature
8997 mapCapabilities .put (DataStoreCapabilities .STORAGE_SYSTEM_SNAPSHOT .toString (), Boolean .FALSE .toString ());
9098 mapCapabilities .put (DataStoreCapabilities .CAN_CREATE_VOLUME_FROM_SNAPSHOT .toString (), Boolean .FALSE .toString ());
99+
91100 return mapCapabilities ;
92101 }
93102
@@ -254,6 +263,7 @@ public void deleteAsync(DataStore store, DataObject data, AsyncCompletionCallbac
254263
255264 @ Override
256265 public void copyAsync (DataObject srcData , DataObject destData , AsyncCompletionCallback <CopyCommandResult > callback ) {
266+
257267 }
258268
259269 @ Override
@@ -525,6 +535,81 @@ public long getUsedIops(StoragePool storagePool) {
525535 @ Override
526536 public void takeSnapshot (SnapshotInfo snapshot , AsyncCompletionCallback <CreateCmdResult > callback ) {
527537
538+ CreateCmdResult result ;
539+
540+ try {
541+ VolumeInfo volumeInfo = snapshot .getBaseVolume ();
542+
543+ VolumeVO volumeVO = volumeDao .findById (volumeInfo .getId ());
544+ if (volumeVO == null ) {
545+ throw new CloudRuntimeException ("takeSnapshot: VolumeVO not found for id: " + volumeInfo .getId ());
546+ }
547+
548+ /** we are keeping file path at volumeVO.getPath() */
549+
550+ StoragePoolVO storagePool = storagePoolDao .findById (volumeVO .getPoolId ());
551+ if (storagePool == null ) {
552+ s_logger .error ("takeSnapshot : Storage Pool not found for id: " + volumeVO .getPoolId ());
553+ throw new CloudRuntimeException ("takeSnapshot : Storage Pool not found for id: " + volumeVO .getPoolId ());
554+ }
555+ Map <String , String > poolDetails = storagePoolDetailsDao .listDetailsKeyPairs (volumeVO .getPoolId ());
556+ StorageStrategy storageStrategy = Utility .getStrategyByStoragePoolDetails (poolDetails );
557+
558+ Map <String , String > cloudStackVolumeRequestMap = new HashMap <>();
559+ cloudStackVolumeRequestMap .put (Constants .VOLUME_UUID , poolDetails .get (Constants .VOLUME_UUID ));
560+ cloudStackVolumeRequestMap .put (Constants .FILE_PATH , volumeVO .getPath ());
561+ CloudStackVolume cloudStackVolume = storageStrategy .getCloudStackVolume (cloudStackVolumeRequestMap );
562+ if (cloudStackVolume == null || cloudStackVolume .getFile () == null ) {
563+ throw new CloudRuntimeException ("takeSnapshot: Failed to get source file to take snapshot" );
564+ }
565+ long capacityBytes = storagePool .getCapacityBytes ();
566+
567+ long usedBytes = getUsedBytes (storagePool );
568+ long fileSize = cloudStackVolume .getFile ().getSize ();
569+
570+ usedBytes += fileSize ;
571+
572+ if (usedBytes > capacityBytes ) {
573+ throw new CloudRuntimeException ("Insufficient space remains in this primary storage to take a snapshot" );
574+ }
575+
576+ storagePool .setUsedBytes (usedBytes );
577+
578+ SnapshotObjectTO snapshotObjectTo = (SnapshotObjectTO )snapshot .getTO ();
579+
580+ String fileSnapshotName = volumeInfo .getName () + "-" + snapshot .getUuid ();
581+
582+ int maxSnapshotNameLength = 64 ;
583+ int trimRequired = fileSnapshotName .length () - maxSnapshotNameLength ;
584+
585+ if (trimRequired > 0 ) {
586+ fileSnapshotName = StringUtils .left (volumeInfo .getName (), (volumeInfo .getName ().length () - trimRequired )) + "-" + snapshot .getUuid ();
587+ }
588+
589+ CloudStackVolume snapCloudStackVolumeRequest = snapshotCloudStackVolumeRequestByProtocol (poolDetails , volumeVO .getPath (), fileSnapshotName );
590+ CloudStackVolume cloneCloudStackVolume = storageStrategy .snapshotCloudStackVolume (snapCloudStackVolumeRequest );
591+
592+ updateSnapshotDetails (snapshot .getId (), volumeInfo .getId (), poolDetails .get (Constants .VOLUME_UUID ), cloneCloudStackVolume .getFile ().getPath (), volumeVO .getPoolId (), fileSize );
593+
594+ snapshotObjectTo .setPath (Constants .ONTAP_SNAP_ID +"=" +cloneCloudStackVolume .getFile ().getPath ());
595+
596+ /** Update size for the storage-pool including snapshot size */
597+ storagePoolDao .update (volumeVO .getPoolId (), storagePool );
598+
599+ CreateObjectAnswer createObjectAnswer = new CreateObjectAnswer (snapshotObjectTo );
600+
601+ result = new CreateCmdResult (null , createObjectAnswer );
602+
603+ result .setResult (null );
604+ }
605+ catch (Exception ex ) {
606+ s_logger .error ("takeSnapshot: Failed due to " , ex );
607+ result = new CreateCmdResult (null , new CreateObjectAnswer (ex .toString ()));
608+
609+ result .setResult (ex .toString ());
610+ }
611+
612+ callback .complete (result );
528613 }
529614
530615 @ Override
@@ -622,4 +707,87 @@ private CloudStackVolume createDeleteCloudStackVolumeRequest(StoragePool storage
622707 return cloudStackVolumeDeleteRequest ;
623708
624709 }
710+
711+
712+ private CloudStackVolume getCloudStackVolumeRequestByProtocol (Map <String , String > details , String filePath ) {
713+ CloudStackVolume cloudStackVolumeRequest = null ;
714+ ProtocolType protocolType = null ;
715+ String protocol = null ;
716+
717+ try {
718+ protocol = details .get (Constants .PROTOCOL );
719+ protocolType = ProtocolType .valueOf (protocol );
720+ } catch (IllegalArgumentException e ) {
721+ throw new CloudRuntimeException ("getCloudStackVolumeRequestByProtocol: Protocol: " + protocol +" is not valid" );
722+ }
723+ switch (protocolType ) {
724+ case NFS3 :
725+ cloudStackVolumeRequest = new CloudStackVolume ();
726+ FileInfo fileInfo = new FileInfo ();
727+ fileInfo .setPath (filePath );
728+ cloudStackVolumeRequest .setFile (fileInfo );
729+ String volumeUuid = details .get (Constants .VOLUME_UUID );
730+ cloudStackVolumeRequest .setFlexVolumeUuid (volumeUuid );
731+ break ;
732+ default :
733+ throw new CloudRuntimeException ("createCloudStackVolumeRequestByProtocol: Unsupported protocol " + protocol );
734+ }
735+ return cloudStackVolumeRequest ;
736+ }
737+
738+ private CloudStackVolume snapshotCloudStackVolumeRequestByProtocol (Map <String , String > details ,
739+ String sourcePath ,
740+ String destinationPath ) {
741+ CloudStackVolume cloudStackVolumeRequest = null ;
742+ ProtocolType protocolType = null ;
743+ String protocol = null ;
744+
745+ try {
746+ protocol = details .get (Constants .PROTOCOL );
747+ protocolType = ProtocolType .valueOf (protocol );
748+ } catch (IllegalArgumentException e ) {
749+ throw new CloudRuntimeException ("getCloudStackVolumeRequestByProtocol: Protocol: " + protocol +" is not valid" );
750+ }
751+ switch (protocolType ) {
752+ case NFS3 :
753+ cloudStackVolumeRequest = new CloudStackVolume ();
754+ FileInfo fileInfo = new FileInfo ();
755+ fileInfo .setPath (sourcePath );
756+ cloudStackVolumeRequest .setFile (fileInfo );
757+ String volumeUuid = details .get (Constants .VOLUME_UUID );
758+ cloudStackVolumeRequest .setFlexVolumeUuid (volumeUuid );
759+ cloudStackVolumeRequest .setDestinationPath (destinationPath );
760+ break ;
761+ default :
762+ throw new CloudRuntimeException ("createCloudStackVolumeRequestByProtocol: Unsupported protocol " + protocol );
763+
764+ }
765+ return cloudStackVolumeRequest ;
766+ }
767+
768+ /**
769+ *
770+ * @param csSnapshotId: generated snapshot id from cloudstack
771+ * @param csVolumeId: Source CS volume id
772+ * @param ontapVolumeUuid: storage flexvolume id
773+ * @param ontapNewSnapshot: generated snapshot id from ONTAP
774+ * @param storagePoolId: primary storage pool id
775+ * @param ontapSnapSize: Size of snapshot CS volume(LUN/file)
776+ */
777+ private void updateSnapshotDetails (long csSnapshotId , long csVolumeId , String ontapVolumeUuid , String ontapNewSnapshot , long storagePoolId , long ontapSnapSize ) {
778+ SnapshotDetailsVO snapshotDetail = new SnapshotDetailsVO (csSnapshotId , Constants .SRC_CS_VOLUME_ID , String .valueOf (csVolumeId ), false );
779+ snapshotDetailsDao .persist (snapshotDetail );
780+
781+ snapshotDetail = new SnapshotDetailsVO (csSnapshotId , Constants .BASE_ONTAP_FV_ID , String .valueOf (ontapVolumeUuid ), false );
782+ snapshotDetailsDao .persist (snapshotDetail );
783+
784+ snapshotDetail = new SnapshotDetailsVO (csSnapshotId , Constants .ONTAP_SNAP_ID , String .valueOf (ontapNewSnapshot ), false );
785+ snapshotDetailsDao .persist (snapshotDetail );
786+
787+ snapshotDetail = new SnapshotDetailsVO (csSnapshotId , Constants .PRIMARY_POOL_ID , String .valueOf (storagePoolId ), false );
788+ snapshotDetailsDao .persist (snapshotDetail );
789+
790+ snapshotDetail = new SnapshotDetailsVO (csSnapshotId , Constants .ONTAP_SNAP_SIZE , String .valueOf (ontapSnapSize ), false );
791+ snapshotDetailsDao .persist (snapshotDetail );
792+ }
625793}
0 commit comments