2525import com .cloud .agent .api .to .DataTO ;
2626import com .cloud .exception .InvalidParameterValueException ;
2727import com .cloud .host .Host ;
28+ import com .cloud .host .HostVO ;
2829import com .cloud .storage .Storage ;
2930import com .cloud .storage .StoragePool ;
3031import com .cloud .storage .Volume ;
3637import com .cloud .storage .dao .VolumeDetailsDao ;
3738import com .cloud .utils .Pair ;
3839import com .cloud .utils .exception .CloudRuntimeException ;
39- import com .cloud .vm .VirtualMachine ;
40- import com .cloud .vm .dao .VMInstanceDao ;
4140import org .apache .cloudstack .engine .subsystem .api .storage .ChapInfo ;
4241import org .apache .cloudstack .engine .subsystem .api .storage .CopyCommandResult ;
4342import org .apache .cloudstack .engine .subsystem .api .storage .CreateCmdResult ;
5453import org .apache .cloudstack .storage .datastore .db .PrimaryDataStoreDao ;
5554import org .apache .cloudstack .storage .datastore .db .StoragePoolDetailsDao ;
5655import org .apache .cloudstack .storage .datastore .db .StoragePoolVO ;
56+ import org .apache .cloudstack .storage .feign .model .Igroup ;
5757import org .apache .cloudstack .storage .feign .client .SnapshotFeignClient ;
5858import org .apache .cloudstack .storage .feign .model .FlexVolSnapshot ;
5959import org .apache .cloudstack .storage .feign .model .Lun ;
7373import org .apache .logging .log4j .Logger ;
7474
7575import javax .inject .Inject ;
76- import java .util .Arrays ;
76+ import java .util .ArrayList ;
7777import java .util .HashMap ;
78+ import java .util .List ;
7879import java .util .Map ;
7980
8081/**
@@ -87,7 +88,6 @@ public class OntapPrimaryDatastoreDriver implements PrimaryDataStoreDriver {
8788
8889 @ Inject private StoragePoolDetailsDao storagePoolDetailsDao ;
8990 @ Inject private PrimaryDataStoreDao storagePoolDao ;
90- @ Inject private VMInstanceDao vmDao ;
9191 @ Inject private VolumeDao volumeDao ;
9292 @ Inject private VolumeDetailsDao volumeDetailsDao ;
9393 @ Inject private SnapshotDetailsDao snapshotDetailsDao ;
@@ -111,6 +111,12 @@ public DataStoreTO getStoreTO(DataStore store) {
111111 return null ;
112112 }
113113
114+ @ Override
115+ public boolean volumesRequireGrantAccessWhenUsed (){
116+ s_logger .info ("OntapPrimaryDatastoreDriver: volumesRequireGrantAccessWhenUsed: Called" );
117+ return true ;
118+ }
119+
114120 /**
115121 * Creates a volume on the ONTAP storage system.
116122 */
@@ -155,7 +161,6 @@ public void createAsync(DataStore dataStore, DataObject dataObject, AsyncComplet
155161 volumeVO .setPoolId (storagePool .getId ());
156162
157163 if (ProtocolType .ISCSI .name ().equalsIgnoreCase (details .get (Constants .PROTOCOL ))) {
158- String svmName = details .get (Constants .SVM_NAME );
159164 String lunName = created != null && created .getLun () != null ? created .getLun ().getName () : null ;
160165 if (lunName == null ) {
161166 throw new CloudRuntimeException ("Missing LUN name for volume " + volInfo .getId ());
@@ -168,22 +173,13 @@ public void createAsync(DataStore dataStore, DataObject dataObject, AsyncComplet
168173 volumeVO .setFolder (created .getLun ().getUuid ());
169174 }
170175
171- // Create LUN-to-igroup mapping and retrieve the assigned LUN ID
172- UnifiedSANStrategy sanStrategy = (UnifiedSANStrategy ) Utility .getStrategyByStoragePoolDetails (details );
173- String accessGroupName = Utility .getIgroupName (svmName , storagePoolUuid );
174- String lunNumber = sanStrategy .ensureLunMapped (svmName , lunName , accessGroupName );
175-
176- // Construct iSCSI path: /<iqn>/<lun_id> format for KVM/libvirt attachment
177- String iscsiPath = Constants .SLASH + storagePool .getPath () + Constants .SLASH + lunNumber ;
178- volumeVO .set_iScsiName (iscsiPath );
179- volumeVO .setPath (iscsiPath );
180- s_logger .info ("createAsync: Volume [{}] iSCSI path set to {}" , volumeVO .getId (), iscsiPath );
181- createCmdResult = new CreateCmdResult (null , new Answer (null , true , null ));
182-
176+ s_logger .info ("createAsync: Created LUN [{}] for volume [{}]. LUN mapping will occur during grantAccess() to per-host igroup." ,
177+ lunName , volumeVO .getId ());
178+ createCmdResult = new CreateCmdResult (lunName , new Answer (null , true , null ));
183179 } else if (ProtocolType .NFS3 .name ().equalsIgnoreCase (details .get (Constants .PROTOCOL ))) {
184180 createCmdResult = new CreateCmdResult (volInfo .getUuid (), new Answer (null , true , null ));
185- s_logger .info ("createAsync: Managed NFS volume [{}] associated with pool {}" ,
186- volumeVO .getId (), storagePool .getId ());
181+ s_logger .info ("createAsync: Managed NFS volume [{}] with path [{}] associated with pool {}" ,
182+ volumeVO .getId (), volInfo . getUuid (), storagePool .getId ());
187183 }
188184 volumeDao .update (volumeVO .getId (), volumeVO );
189185 }
@@ -413,14 +409,35 @@ public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore
413409 // Only retrieve LUN name for iSCSI volumes
414410 String cloudStackVolumeName = volumeDetailsDao .findDetail (volumeVO .getId (), Constants .LUN_DOT_NAME ).getValue ();
415411 UnifiedSANStrategy sanStrategy = (UnifiedSANStrategy ) Utility .getStrategyByStoragePoolDetails (details );
416- String accessGroupName = Utility .getIgroupName (svmName , storagePoolUuid );
417-
418- // Verify host initiator is registered in the igroup before allowing access
419- if (!sanStrategy .validateInitiatorInAccessGroup (host .getStorageUrl (), svmName , accessGroupName )) {
420- throw new CloudRuntimeException ("Host initiator [" + host .getStorageUrl () +
421- "] is not present in iGroup [" + accessGroupName + "]" );
412+ String accessGroupName = Utility .getIgroupName (svmName , host .getName ());
413+
414+ // Validate if Igroup exist ONTAP for this host as we may be using delete_on_unmap= true and igroup may be deleted by ONTAP automatically
415+ Map <String , String > getAccessGroupMap = Map .of (
416+ Constants .NAME , accessGroupName ,
417+ Constants .SVM_DOT_NAME , svmName
418+ );
419+ Igroup igroup = new Igroup ();
420+ AccessGroup accessGroup = sanStrategy .getAccessGroup (getAccessGroupMap );
421+ if (accessGroup == null || accessGroup .getIgroup () == null ) {
422+ s_logger .info ("grantAccess: Igroup {} does not exist for the host {} : Need to create Igroup for the host " , accessGroupName , host .getName ());
423+ // create the igroup for the host and perform lun-mapping
424+ accessGroup = new AccessGroup ();
425+ List <HostVO > hosts = new ArrayList <>();
426+ hosts .add ((HostVO ) host );
427+ accessGroup .setHostsToConnect (hosts );
428+ accessGroup .setStoragePoolId (storagePool .getId ());
429+ accessGroup = sanStrategy .createAccessGroup (accessGroup );
430+ }else {
431+ s_logger .info ("grantAccess: Igroup {} already exist for the host {}: " , accessGroup .getIgroup ().getName () ,host .getName ());
432+ igroup = accessGroup .getIgroup ();
433+ /* TODO Below cases will be covered later, for now they will be a pre-requisite on customer side
434+ 1. Igroup exist with the same name but host initiator has been rempved
435+ 2. Igroup exist with the same name but host initiator has been changed may be due to new NIC or new adapter
436+ In both cases we need to verify current host initiator is registered in the igroup before allowing access
437+ Incase it is not , add it and proceed for lun-mapping
438+ */
422439 }
423-
440+ s_logger . info ( "grantAccess: Igroup {} is present now with initiators {} " , accessGroup . getIgroup (). getName (), accessGroup . getIgroup (). getInitiators ());
424441 // Create or retrieve existing LUN mapping
425442 String lunNumber = sanStrategy .ensureLunMapped (svmName , cloudStackVolumeName , accessGroupName );
426443
@@ -465,22 +482,6 @@ public void revokeAccess(DataObject dataObject, Host host, DataStore dataStore)
465482 throw new InvalidParameterValueException ("host should not be null" );
466483 }
467484
468- // Safety check: don't revoke access if volume is still attached to an active VM
469- if (dataObject .getType () == DataObjectType .VOLUME ) {
470- Volume volume = volumeDao .findById (dataObject .getId ());
471- if (volume .getInstanceId () != null ) {
472- VirtualMachine vm = vmDao .findById (volume .getInstanceId ());
473- if (vm != null && !Arrays .asList (
474- VirtualMachine .State .Destroyed ,
475- VirtualMachine .State .Expunging ,
476- VirtualMachine .State .Error ).contains (vm .getState ())) {
477- s_logger .warn ("revokeAccess: Volume [{}] is still attached to VM [{}] in state [{}], skipping revokeAccess" ,
478- dataObject .getId (), vm .getInstanceName (), vm .getState ());
479- return ;
480- }
481- }
482- }
483-
484485 StoragePoolVO storagePool = storagePoolDao .findById (dataStore .getId ());
485486 if (storagePool == null ) {
486487 s_logger .error ("revokeAccess: Storage Pool not found for id: " + dataStore .getId ());
@@ -518,10 +519,9 @@ private void revokeAccessForVolume(StoragePoolVO storagePool, VolumeVO volumeVO,
518519 Map <String , String > details = storagePoolDetailsDao .listDetailsKeyPairs (storagePool .getId ());
519520 StorageStrategy storageStrategy = Utility .getStrategyByStoragePoolDetails (details );
520521 String svmName = details .get (Constants .SVM_NAME );
521- String storagePoolUuid = storagePool .getUuid ();
522522
523523 if (ProtocolType .ISCSI .name ().equalsIgnoreCase (details .get (Constants .PROTOCOL ))) {
524- String accessGroupName = Utility .getIgroupName (svmName , storagePoolUuid );
524+ String accessGroupName = Utility .getIgroupName (svmName , host . getName () );
525525
526526 // Retrieve LUN name from volume details; if missing, volume may not have been fully created
527527 String lunName = volumeDetailsDao .findDetail (volumeVO .getId (), Constants .LUN_DOT_NAME ) != null ?
@@ -547,7 +547,7 @@ private void revokeAccessForVolume(StoragePoolVO storagePool, VolumeVO volumeVO,
547547
548548 // Verify host initiator is in the igroup before attempting to remove mapping
549549 SANStrategy sanStrategy = (UnifiedSANStrategy ) storageStrategy ;
550- if (!sanStrategy .validateInitiatorInAccessGroup (host .getStorageUrl (), svmName , accessGroup .getIgroup (). getName () )) {
550+ if (!sanStrategy .validateInitiatorInAccessGroup (host .getStorageUrl (), svmName , accessGroup .getIgroup ())) {
551551 s_logger .warn ("revokeAccessForVolume: Initiator [{}] is not in iGroup [{}], skipping revoke" ,
552552 host .getStorageUrl (), accessGroupName );
553553 return ;
@@ -916,7 +916,6 @@ public boolean isVmInfoNeeded() {
916916
917917 @ Override
918918 public void provideVmInfo (long vmId , long volumeId ) {
919-
920919 }
921920
922921 @ Override
0 commit comments