6969
7070/**
7171 * Primary datastore driver for NetApp ONTAP storage systems.
72- * This driver handles volume lifecycle operations (create, delete, grant/revoke access)
73- * for both iSCSI (LUN-based) and NFS protocols against ONTAP storage backends.
74- *
75- * For iSCSI protocol:
76- * - Creates LUNs on ONTAP and maps them to initiator groups (igroups)
77- * - Manages LUN mappings for host access control
78- *
79- * For NFS protocol:
80- * - Delegates file operations to KVM host/libvirt
81- * - ONTAP volume/export management handled at storage pool creation time
72+ * Handles volume lifecycle operations for iSCSI and NFS protocols.
8273 */
8374public class OntapPrimaryDatastoreDriver implements PrimaryDataStoreDriver {
8475
@@ -111,26 +102,16 @@ public DataStoreTO getStoreTO(DataStore store) {
111102 }
112103
113104 /**
114- * Asynchronously creates a volume on the ONTAP storage system.
115- *
116- * For iSCSI protocol:
117- * - Creates a LUN on ONTAP via the SAN strategy
118- * - Stores LUN UUID and name in volume_details table for later reference
119- * - Creates a LUN mapping to the appropriate igroup (based on cluster/zone scope)
120- * - Sets the iSCSI path on the volume for host attachment
121- *
122- * For NFS protocol:
123- * - Associates the volume with the storage pool (actual file creation handled by hypervisor)
124- *
125- * @param dataStore The target data store (storage pool)
126- * @param dataObject The volume to create
127- * @param callback Callback to notify completion
105+ * Creates a volume on the ONTAP storage system.
128106 */
129107 @ Override
130108 public void createAsync (DataStore dataStore , DataObject dataObject , AsyncCompletionCallback <CreateCmdResult > callback ) {
131109 CreateCmdResult createCmdResult = null ;
132110 String errMsg ;
133111
112+ if (dataObject == null ) {
113+ throw new InvalidParameterValueException ("createAsync: dataObject should not be null" );
114+ }
134115 if (dataStore == null ) {
135116 throw new InvalidParameterValueException ("createAsync: dataStore should not be null" );
136117 }
@@ -150,6 +131,7 @@ public void createAsync(DataStore dataStore, DataObject dataObject, AsyncComplet
150131 s_logger .error ("createAsync: Storage Pool not found for id: " + dataStore .getId ());
151132 throw new CloudRuntimeException ("createAsync: Storage Pool not found for id: " + dataStore .getId ());
152133 }
134+ String storagePoolUuid = dataStore .getUuid ();
153135
154136 Map <String , String > details = storagePoolDetailsDao .listDetailsKeyPairs (dataStore .getId ());
155137
@@ -186,7 +168,7 @@ public void createAsync(DataStore dataStore, DataObject dataObject, AsyncComplet
186168
187169 // Create LUN-to-igroup mapping and retrieve the assigned LUN ID
188170 UnifiedSANStrategy sanStrategy = (UnifiedSANStrategy ) Utility .getStrategyByStoragePoolDetails (details );
189- String accessGroupName = Utility .getIgroupName (svmName , storagePool . getScope (), scopeId );
171+ String accessGroupName = Utility .getIgroupName (svmName , storagePoolUuid );
190172 String lunNumber = sanStrategy .ensureLunMapped (svmName , lunName , accessGroupName );
191173
192174 // Construct iSCSI path: /<iqn>/<lun_id> format for KVM/libvirt attachment
@@ -223,12 +205,7 @@ public void createAsync(DataStore dataStore, DataObject dataObject, AsyncComplet
223205 }
224206
225207 /**
226- * Creates a CloudStack volume on the ONTAP backend using the appropriate storage strategy.
227- *
228- * @param dataStore The target data store
229- * @param dataObject The volume to create
230- * @param details Storage pool configuration details
231- * @return CloudStackVolume containing the created backend object (LUN for iSCSI)
208+ * Creates a volume on the ONTAP backend.
232209 */
233210 private CloudStackVolume createCloudStackVolume (DataStore dataStore , DataObject dataObject , Map <String , String > details ) {
234211 StoragePoolVO storagePool = storagePoolDao .findById (dataStore .getId ());
@@ -249,18 +226,7 @@ private CloudStackVolume createCloudStackVolume(DataStore dataStore, DataObject
249226 }
250227
251228 /**
252- * Asynchronously deletes a volume from the ONTAP storage system.
253- *
254- * For iSCSI protocol:
255- * - Retrieves LUN details from volume_details table
256- * - Deletes the LUN from ONTAP (LUN mappings are automatically removed)
257- *
258- * For NFS protocol:
259- * - No ONTAP operation needed; file deletion handled by KVM host/libvirt
260- *
261- * @param store The data store containing the volume
262- * @param data The volume to delete
263- * @param callback Callback to notify completion
229+ * Deletes a volume from the ONTAP storage system.
264230 */
265231 @ Override
266232 public void deleteAsync (DataStore store , DataObject data , AsyncCompletionCallback <CommandResult > callback ) {
@@ -344,20 +310,7 @@ public ChapInfo getChapInfo(DataObject dataObject) {
344310 }
345311
346312 /**
347- * Grants a host access to a volume on the ONTAP storage system.
348- *
349- * For iSCSI protocol:
350- * - Validates that the host's iSCSI initiator (IQN) is present in the target igroup
351- * - Ensures the LUN is mapped to the igroup (creates mapping if not exists)
352- * - Updates the volume's iSCSI path with the assigned LUN ID
353- *
354- * For NFS protocol:
355- * - No explicit grant needed; NFS exports are configured at storage pool level
356- *
357- * @param dataObject The volume to grant access to
358- * @param host The host requesting access
359- * @param dataStore The data store containing the volume
360- * @return true if access was granted successfully
313+ * Grants a host access to a volume.
361314 */
362315 @ Override
363316 public boolean grantAccess (DataObject dataObject , Host host , DataStore dataStore ) {
@@ -377,6 +330,7 @@ public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore
377330 s_logger .error ("grantAccess: Storage Pool not found for id: " + dataStore .getId ());
378331 throw new CloudRuntimeException ("grantAccess: Storage Pool not found for id: " + dataStore .getId ());
379332 }
333+ String storagePoolUuid = dataStore .getUuid ();
380334
381335 // ONTAP managed storage only supports cluster and zone scoped pools
382336 if (storagePool .getScope () != ScopeType .CLUSTER && storagePool .getScope () != ScopeType .ZONE ) {
@@ -398,7 +352,7 @@ public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore
398352
399353 if (ProtocolType .ISCSI .name ().equalsIgnoreCase (details .get (Constants .PROTOCOL ))) {
400354 UnifiedSANStrategy sanStrategy = (UnifiedSANStrategy ) Utility .getStrategyByStoragePoolDetails (details );
401- String accessGroupName = Utility .getIgroupName (svmName , storagePool . getScope (), scopeId );
355+ String accessGroupName = Utility .getIgroupName (svmName , storagePoolUuid );
402356
403357 // Verify host initiator is registered in the igroup before allowing access
404358 if (!sanStrategy .validateInitiatorInAccessGroup (host .getStorageUrl (), svmName , accessGroupName )) {
@@ -432,18 +386,7 @@ public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore
432386 }
433387
434388 /**
435- * Revokes a host's access to a volume on the ONTAP storage system.
436- *
437- * For iSCSI protocol:
438- * - Validates the volume is not attached to an active VM
439- * - Removes the LUN mapping from the igroup
440- *
441- * For NFS protocol:
442- * - No explicit revoke needed; NFS exports remain at storage pool level
443- *
444- * @param dataObject The volume to revoke access from
445- * @param host The host losing access
446- * @param dataStore The data store containing the volume
389+ * Revokes a host's access to a volume.
447390 */
448391 @ Override
449392 public void revokeAccess (DataObject dataObject , Host host , DataStore dataStore ) {
@@ -467,7 +410,7 @@ public void revokeAccess(DataObject dataObject, Host host, DataStore dataStore)
467410 VirtualMachine .State .Destroyed ,
468411 VirtualMachine .State .Expunging ,
469412 VirtualMachine .State .Error ).contains (vm .getState ())) {
470- s_logger .debug ("revokeAccess: Volume [{}] is still attached to VM [{}] in state [{}], skipping revokeAccess" ,
413+ s_logger .warn ("revokeAccess: Volume [{}] is still attached to VM [{}] in state [{}], skipping revokeAccess" ,
471414 dataObject .getId (), vm .getInstanceName (), vm .getState ());
472415 return ;
473416 }
@@ -503,23 +446,19 @@ public void revokeAccess(DataObject dataObject, Host host, DataStore dataStore)
503446 }
504447
505448 /**
506- * Revokes volume access by removing the LUN mapping from the igroup.
507- * This method handles the iSCSI-specific logic for access revocation.
508- *
509- * @param storagePool The storage pool containing the volume
510- * @param volumeVO The volume to revoke access from
511- * @param host The host losing access
449+ * Revokes volume access for the specified host.
512450 */
513451 private void revokeAccessForVolume (StoragePoolVO storagePool , VolumeVO volumeVO , Host host ) {
514452 s_logger .info ("revokeAccessForVolume: Revoking access to volume [{}] for host [{}]" , volumeVO .getName (), host .getName ());
515453
516454 Map <String , String > details = storagePoolDetailsDao .listDetailsKeyPairs (storagePool .getId ());
517455 StorageStrategy storageStrategy = Utility .getStrategyByStoragePoolDetails (details );
518456 String svmName = details .get (Constants .SVM_NAME );
457+ String storagePoolUuid = storagePool .getUuid ();
519458 long scopeId = (storagePool .getScope () == ScopeType .CLUSTER ) ? host .getClusterId () : host .getDataCenterId ();
520459
521460 if (ProtocolType .ISCSI .name ().equalsIgnoreCase (details .get (Constants .PROTOCOL ))) {
522- String accessGroupName = Utility .getIgroupName (svmName , storagePool . getScope (), scopeId );
461+ String accessGroupName = Utility .getIgroupName (svmName , storagePoolUuid );
523462
524463 // Retrieve LUN name from volume details; if missing, volume may not have been fully created
525464 String lunName = volumeDetailsDao .findDetail (volumeVO .getId (), Constants .LUN_DOT_NAME ) != null ?
@@ -563,12 +502,7 @@ private void revokeAccessForVolume(StoragePoolVO storagePool, VolumeVO volumeVO,
563502 }
564503
565504 /**
566- * Retrieves a CloudStack volume (LUN) from ONTAP by name.
567- *
568- * @param storageStrategy The storage strategy to use for the lookup
569- * @param svmName The SVM name containing the LUN
570- * @param cloudStackVolumeName The LUN name to look up
571- * @return CloudStackVolume if found, null otherwise
505+ * Retrieves a volume from ONTAP by name.
572506 */
573507 private CloudStackVolume getCloudStackVolumeByName (StorageStrategy storageStrategy , String svmName , String cloudStackVolumeName ) {
574508 Map <String , String > getCloudStackVolumeMap = new HashMap <>();
@@ -584,12 +518,7 @@ private CloudStackVolume getCloudStackVolumeByName(StorageStrategy storageStrate
584518 }
585519
586520 /**
587- * Retrieves an access group (igroup) from ONTAP by name.
588- *
589- * @param storageStrategy The storage strategy to use for the lookup
590- * @param svmName The SVM name containing the igroup
591- * @param accessGroupName The igroup name to look up
592- * @return AccessGroup if found, null otherwise
521+ * Retrieves an access group from ONTAP by name.
593522 */
594523 private AccessGroup getAccessGroupByName (StorageStrategy storageStrategy , String svmName , String accessGroupName ) {
595524 Map <String , String > getAccessGroupMap = new HashMap <>();
0 commit comments