1818 */
1919package org .apache .cloudstack .storage .driver ;
2020
21+ import com .cloud .agent .api .Answer ;
22+ import com .cloud .agent .api .to .DataObjectType ;
2123import com .cloud .agent .api .to .DataStoreTO ;
2224import com .cloud .agent .api .to .DataTO ;
25+ import com .cloud .exception .InvalidParameterValueException ;
2326import com .cloud .host .Host ;
2427import com .cloud .storage .Storage ;
2528import com .cloud .storage .StoragePool ;
4043import org .apache .cloudstack .storage .command .CommandResult ;
4144import org .apache .cloudstack .storage .datastore .db .PrimaryDataStoreDao ;
4245import org .apache .cloudstack .storage .datastore .db .StoragePoolDetailsDao ;
43- import org .apache .cloudstack .storage .feign .model .OntapStorage ;
44- import org .apache .cloudstack .storage .provider .StorageProviderFactory ;
46+ import org .apache .cloudstack .storage .datastore .db .StoragePoolVO ;
4547import org .apache .cloudstack .storage .service .StorageStrategy ;
48+ import org .apache .cloudstack .storage .service .model .CloudStackVolume ;
4649import org .apache .cloudstack .storage .service .model .ProtocolType ;
4750import org .apache .cloudstack .storage .utils .Constants ;
51+ import org .apache .cloudstack .storage .utils .Utility ;
4852import org .apache .logging .log4j .LogManager ;
4953import org .apache .logging .log4j .Logger ;
5054
@@ -58,13 +62,15 @@ public class OntapPrimaryDatastoreDriver implements PrimaryDataStoreDriver {
5862
5963 @ Inject private StoragePoolDetailsDao storagePoolDetailsDao ;
6064 @ Inject private PrimaryDataStoreDao storagePoolDao ;
65+
6166 @ Override
6267 public Map <String , String > getCapabilities () {
6368 s_logger .trace ("OntapPrimaryDatastoreDriver: getCapabilities: Called" );
6469 Map <String , String > mapCapabilities = new HashMap <>();
65-
66- mapCapabilities .put (DataStoreCapabilities .STORAGE_SYSTEM_SNAPSHOT .toString (), Boolean .TRUE .toString ());
67- mapCapabilities .put (DataStoreCapabilities .CAN_CREATE_VOLUME_FROM_SNAPSHOT .toString (), Boolean .TRUE .toString ());
70+ // RAW managed initial implementation: snapshot features not yet supported
71+ // TODO Set it to false once we start supporting snapshot feature
72+ mapCapabilities .put (DataStoreCapabilities .STORAGE_SYSTEM_SNAPSHOT .toString (), Boolean .FALSE .toString ());
73+ mapCapabilities .put (DataStoreCapabilities .CAN_CREATE_VOLUME_FROM_SNAPSHOT .toString (), Boolean .FALSE .toString ());
6874
6975 return mapCapabilities ;
7076 }
@@ -75,18 +81,93 @@ public DataTO getTO(DataObject data) {
7581 }
7682
7783 @ Override
78- public DataStoreTO getStoreTO (DataStore store ) {
79- return null ;
80- }
84+ public DataStoreTO getStoreTO (DataStore store ) { return null ; }
8185
8286 @ Override
8387 public void createAsync (DataStore dataStore , DataObject dataObject , AsyncCompletionCallback <CreateCmdResult > callback ) {
88+ CreateCmdResult createCmdResult = null ;
89+ String path = null ;
90+ String errMsg = null ;
91+ if (dataStore == null ) {
92+ throw new InvalidParameterValueException ("createAsync: dataStore should not be null" );
93+ }
94+ if (dataObject == null ) {
95+ throw new InvalidParameterValueException ("createAsync: dataObject should not be null" );
96+ }
97+ if (callback == null ) {
98+ throw new InvalidParameterValueException ("createAsync: callback should not be null" );
99+ }
100+ try {
101+ s_logger .info ("createAsync: Started for data store [{}] and data object [{}] of type [{}]" ,
102+ dataStore , dataObject , dataObject .getType ());
103+ if (dataObject .getType () == DataObjectType .VOLUME ) {
104+ VolumeInfo volumeInfo = (VolumeInfo ) dataObject ;
105+ path = createCloudStackVolumeForTypeVolume (dataStore , volumeInfo );
106+ createCmdResult = new CreateCmdResult (path , new Answer (null , true , null ));
107+ } else {
108+ errMsg = "Invalid DataObjectType (" + dataObject .getType () + ") passed to createAsync" ;
109+ s_logger .error (errMsg );
110+ throw new CloudRuntimeException (errMsg );
111+ }
112+ } catch (Exception e ) {
113+ errMsg = e .getMessage ();
114+ s_logger .error ("createAsync: Failed for dataObject [{}]: {}" , dataObject , errMsg );
115+ createCmdResult = new CreateCmdResult (null , new Answer (null , false , errMsg ));
116+ createCmdResult .setResult (e .toString ());
117+ } finally {
118+ if (createCmdResult != null && createCmdResult .isSuccess ()) {
119+ s_logger .info ("createAsync: Volume created successfully. Path: {}" , path );
120+ }
121+ callback .complete (createCmdResult );
122+ }
123+ }
84124
125+ private String createCloudStackVolumeForTypeVolume (DataStore dataStore , VolumeInfo volumeObject ) {
126+ StoragePoolVO storagePool = storagePoolDao .findById (dataStore .getId ());
127+ if (storagePool == null ) {
128+ s_logger .error ("createCloudStackVolume : Storage Pool not found for id: " + dataStore .getId ());
129+ throw new CloudRuntimeException ("createCloudStackVolume : Storage Pool not found for id: " + dataStore .getId ());
130+ }
131+ Map <String , String > details = storagePoolDetailsDao .listDetailsKeyPairs (dataStore .getId ());
132+ StorageStrategy storageStrategy = Utility .getStrategyByStoragePoolDetails (details );
133+ s_logger .info ("createCloudStackVolumeForTypeVolume: Connection to Ontap SVM [{}] successful, preparing CloudStackVolumeRequest" , details .get (Constants .SVM_NAME ));
134+ CloudStackVolume cloudStackVolumeRequest = Utility .createCloudStackVolumeRequestByProtocol (storagePool , details , volumeObject );
135+ CloudStackVolume cloudStackVolume = storageStrategy .createCloudStackVolume (cloudStackVolumeRequest );
136+ if (ProtocolType .ISCSI .name ().equalsIgnoreCase (details .get (Constants .PROTOCOL )) && cloudStackVolume .getLun () != null && cloudStackVolume .getLun ().getName () != null ) {
137+ return cloudStackVolume .getLun ().getName ();
138+ } else if (ProtocolType .NFS3 .name ().equalsIgnoreCase (details .get (Constants .PROTOCOL ))) {
139+ return volumeObject .getUuid (); // return the volume UUID for agent as path for mounting
140+ } else {
141+ String errMsg = "createCloudStackVolumeForTypeVolume: Volume creation failed. Lun or Lun Path is null for dataObject: " + volumeObject ;
142+ s_logger .error (errMsg );
143+ throw new CloudRuntimeException (errMsg );
144+ }
85145 }
86146
87147 @ Override
88148 public void deleteAsync (DataStore store , DataObject data , AsyncCompletionCallback <CommandResult > callback ) {
89-
149+ CommandResult commandResult = new CommandResult ();
150+ try {
151+ if (store == null || data == null ) {
152+ throw new CloudRuntimeException ("deleteAsync: store or data is null" );
153+ }
154+ if (data .getType () == DataObjectType .VOLUME ) {
155+ StoragePoolVO storagePool = storagePoolDao .findById (store .getId ());
156+ if (storagePool == null ) {
157+ s_logger .error ("deleteAsync : Storage Pool not found for id: " + store .getId ());
158+ throw new CloudRuntimeException ("deleteAsync : Storage Pool not found for id: " + store .getId ());
159+ }
160+ Map <String , String > details = storagePoolDetailsDao .listDetailsKeyPairs (store .getId ());
161+ if (ProtocolType .NFS3 .name ().equalsIgnoreCase (details .get (Constants .PROTOCOL ))) {
162+ // ManagedNFS qcow2 backing file deletion handled by KVM host/libvirt; nothing to do via ONTAP REST.
163+ s_logger .info ("deleteAsync: ManagedNFS volume {} no-op ONTAP deletion" , data .getId ());
164+ }
165+ }
166+ } catch (Exception e ) {
167+ commandResult .setResult (e .getMessage ());
168+ } finally {
169+ callback .complete (commandResult );
170+ }
90171 }
91172
92173 @ Override
@@ -121,7 +202,6 @@ public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore
121202
122203 @ Override
123204 public void revokeAccess (DataObject dataObject , Host host , DataStore dataStore ) {
124-
125205 }
126206
127207 @ Override
@@ -161,7 +241,7 @@ public void handleQualityOfServiceForVolumeMigration(VolumeInfo volumeInfo, Qual
161241
162242 @ Override
163243 public boolean canProvideStorageStats () {
164- return true ;
244+ return false ;
165245 }
166246
167247 @ Override
@@ -171,7 +251,7 @@ public Pair<Long, Long> getStorageStats(StoragePool storagePool) {
171251
172252 @ Override
173253 public boolean canProvideVolumeStats () {
174- return true ;
254+ return false ; // Not yet implemented for RAW managed NFS
175255 }
176256
177257 @ Override
@@ -213,24 +293,4 @@ public boolean isStorageSupportHA(Storage.StoragePoolType type) {
213293 public void detachVolumeFromAllStorageNodes (Volume volume ) {
214294
215295 }
216-
217- private StorageStrategy getStrategyByStoragePoolDetails (Map <String , String > details ) {
218- if (details == null || details .isEmpty ()) {
219- s_logger .error ("getStrategyByStoragePoolDetails: Storage pool details are null or empty" );
220- throw new CloudRuntimeException ("getStrategyByStoragePoolDetails: Storage pool details are null or empty" );
221- }
222- String protocol = details .get (Constants .PROTOCOL );
223- OntapStorage ontapStorage = new OntapStorage (details .get (Constants .USERNAME ), details .get (Constants .PASSWORD ),
224- details .get (Constants .MANAGEMENT_LIF ), details .get (Constants .SVM_NAME ), Long .parseLong (details .get (Constants .SIZE )), ProtocolType .valueOf (protocol ),
225- Boolean .parseBoolean (details .get (Constants .IS_DISAGGREGATED )));
226- StorageStrategy storageStrategy = StorageProviderFactory .getStrategy (ontapStorage );
227- boolean isValid = storageStrategy .connect ();
228- if (isValid ) {
229- s_logger .info ("Connection to Ontap SVM [{}] successful" , details .get (Constants .SVM_NAME ));
230- return storageStrategy ;
231- } else {
232- s_logger .error ("getStrategyByStoragePoolDetails: Connection to Ontap SVM [" + details .get (Constants .SVM_NAME ) + "] failed" );
233- throw new CloudRuntimeException ("getStrategyByStoragePoolDetails: Connection to Ontap SVM [" + details .get (Constants .SVM_NAME ) + "] failed" );
234- }
235- }
236296}
0 commit comments