2424import com .cloud .agent .api .to .DataTO ;
2525import com .cloud .exception .InvalidParameterValueException ;
2626import com .cloud .host .Host ;
27+ import com .cloud .host .HostVO ;
2728import com .cloud .storage .Storage ;
2829import com .cloud .storage .StoragePool ;
2930import com .cloud .storage .Volume ;
3536import com .cloud .storage .dao .VolumeDetailsDao ;
3637import com .cloud .utils .Pair ;
3738import com .cloud .utils .exception .CloudRuntimeException ;
38- import com .cloud .vm .VirtualMachine ;
39- import com .cloud .vm .dao .VMInstanceDao ;
4039import org .apache .cloudstack .engine .subsystem .api .storage .ChapInfo ;
4140import org .apache .cloudstack .engine .subsystem .api .storage .CopyCommandResult ;
4241import org .apache .cloudstack .engine .subsystem .api .storage .CreateCmdResult ;
5352import org .apache .cloudstack .storage .datastore .db .PrimaryDataStoreDao ;
5453import org .apache .cloudstack .storage .datastore .db .StoragePoolDetailsDao ;
5554import org .apache .cloudstack .storage .datastore .db .StoragePoolVO ;
55+ import org .apache .cloudstack .storage .feign .model .Igroup ;
5656import org .apache .cloudstack .storage .feign .client .SnapshotFeignClient ;
5757import org .apache .cloudstack .storage .feign .model .FlexVolSnapshot ;
5858import org .apache .cloudstack .storage .feign .model .Lun ;
7272import org .apache .logging .log4j .Logger ;
7373
7474import javax .inject .Inject ;
75- import java .util .Arrays ;
75+ import java .util .ArrayList ;
7676import java .util .HashMap ;
77+ import java .util .List ;
7778import java .util .Map ;
7879
7980/**
@@ -86,7 +87,6 @@ public class OntapPrimaryDatastoreDriver implements PrimaryDataStoreDriver {
8687
8788 @ Inject private StoragePoolDetailsDao storagePoolDetailsDao ;
8889 @ Inject private PrimaryDataStoreDao storagePoolDao ;
89- @ Inject private VMInstanceDao vmDao ;
9090 @ Inject private VolumeDao volumeDao ;
9191 @ Inject private VolumeDetailsDao volumeDetailsDao ;
9292 @ Inject private SnapshotDetailsDao snapshotDetailsDao ;
@@ -110,6 +110,12 @@ public DataStoreTO getStoreTO(DataStore store) {
110110 return null ;
111111 }
112112
113+ @ Override
114+ public boolean volumesRequireGrantAccessWhenUsed (){
115+ s_logger .info ("OntapPrimaryDatastoreDriver: volumesRequireGrantAccessWhenUsed: Called" );
116+ return true ;
117+ }
118+
113119 /**
114120 * Creates a volume on the ONTAP storage system.
115121 */
@@ -154,7 +160,6 @@ public void createAsync(DataStore dataStore, DataObject dataObject, AsyncComplet
154160 volumeVO .setPoolId (storagePool .getId ());
155161
156162 if (ProtocolType .ISCSI .name ().equalsIgnoreCase (details .get (Constants .PROTOCOL ))) {
157- String svmName = details .get (Constants .SVM_NAME );
158163 String lunName = created != null && created .getLun () != null ? created .getLun ().getName () : null ;
159164 if (lunName == null ) {
160165 throw new CloudRuntimeException ("Missing LUN name for volume " + volInfo .getId ());
@@ -167,22 +172,13 @@ public void createAsync(DataStore dataStore, DataObject dataObject, AsyncComplet
167172 volumeVO .setFolder (created .getLun ().getUuid ());
168173 }
169174
170- // Create LUN-to-igroup mapping and retrieve the assigned LUN ID
171- UnifiedSANStrategy sanStrategy = (UnifiedSANStrategy ) Utility .getStrategyByStoragePoolDetails (details );
172- String accessGroupName = Utility .getIgroupName (svmName , storagePoolUuid );
173- String lunNumber = sanStrategy .ensureLunMapped (svmName , lunName , accessGroupName );
174-
175- // Construct iSCSI path: /<iqn>/<lun_id> format for KVM/libvirt attachment
176- String iscsiPath = Constants .SLASH + storagePool .getPath () + Constants .SLASH + lunNumber ;
177- volumeVO .set_iScsiName (iscsiPath );
178- volumeVO .setPath (iscsiPath );
179- s_logger .info ("createAsync: Volume [{}] iSCSI path set to {}" , volumeVO .getId (), iscsiPath );
180- createCmdResult = new CreateCmdResult (null , new Answer (null , true , null ));
181-
175+ s_logger .info ("createAsync: Created LUN [{}] for volume [{}]. LUN mapping will occur during grantAccess() to per-host igroup." ,
176+ lunName , volumeVO .getId ());
177+ createCmdResult = new CreateCmdResult (lunName , new Answer (null , true , null ));
182178 } else if (ProtocolType .NFS3 .name ().equalsIgnoreCase (details .get (Constants .PROTOCOL ))) {
183179 createCmdResult = new CreateCmdResult (volInfo .getUuid (), new Answer (null , true , null ));
184- s_logger .info ("createAsync: Managed NFS volume [{}] associated with pool {}" ,
185- volumeVO .getId (), storagePool .getId ());
180+ s_logger .info ("createAsync: Managed NFS volume [{}] with path [{}] associated with pool {}" ,
181+ volumeVO .getId (), volInfo . getUuid (), storagePool .getId ());
186182 }
187183 volumeDao .update (volumeVO .getId (), volumeVO );
188184 }
@@ -412,14 +408,35 @@ public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore
412408 // Only retrieve LUN name for iSCSI volumes
413409 String cloudStackVolumeName = volumeDetailsDao .findDetail (volumeVO .getId (), Constants .LUN_DOT_NAME ).getValue ();
414410 UnifiedSANStrategy sanStrategy = (UnifiedSANStrategy ) Utility .getStrategyByStoragePoolDetails (details );
415- String accessGroupName = Utility .getIgroupName (svmName , storagePoolUuid );
416-
417- // Verify host initiator is registered in the igroup before allowing access
418- if (!sanStrategy .validateInitiatorInAccessGroup (host .getStorageUrl (), svmName , accessGroupName )) {
419- throw new CloudRuntimeException ("Host initiator [" + host .getStorageUrl () +
420- "] is not present in iGroup [" + accessGroupName + "]" );
411+ String accessGroupName = Utility .getIgroupName (svmName , host .getName ());
412+
413+ // 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
414+ Map <String , String > getAccessGroupMap = Map .of (
415+ Constants .NAME , accessGroupName ,
416+ Constants .SVM_DOT_NAME , svmName
417+ );
418+ Igroup igroup = new Igroup ();
419+ AccessGroup accessGroup = sanStrategy .getAccessGroup (getAccessGroupMap );
420+ if (accessGroup == null || accessGroup .getIgroup () == null ) {
421+ s_logger .info ("grantAccess: Igroup {} does not exist for the host {} : Need to create Igroup for the host " , accessGroupName , host .getName ());
422+ // create the igroup for the host and perform lun-mapping
423+ accessGroup = new AccessGroup ();
424+ List <HostVO > hosts = new ArrayList <>();
425+ hosts .add ((HostVO ) host );
426+ accessGroup .setHostsToConnect (hosts );
427+ accessGroup .setStoragePoolId (storagePool .getId ());
428+ accessGroup = sanStrategy .createAccessGroup (accessGroup );
429+ }else {
430+ s_logger .info ("grantAccess: Igroup {} already exist for the host {}: " , accessGroup .getIgroup ().getName () ,host .getName ());
431+ igroup = accessGroup .getIgroup ();
432+ /* TODO Below cases will be covered later, for now they will be a pre-requisite on customer side
433+ 1. Igroup exist with the same name but host initiator has been rempved
434+ 2. Igroup exist with the same name but host initiator has been changed may be due to new NIC or new adapter
435+ In both cases we need to verify current host initiator is registered in the igroup before allowing access
436+ Incase it is not , add it and proceed for lun-mapping
437+ */
421438 }
422-
439+ s_logger . info ( "grantAccess: Igroup {} is present now with initiators {} " , accessGroup . getIgroup (). getName (), accessGroup . getIgroup (). getInitiators ());
423440 // Create or retrieve existing LUN mapping
424441 String lunNumber = sanStrategy .ensureLunMapped (svmName , cloudStackVolumeName , accessGroupName );
425442
@@ -464,22 +481,6 @@ public void revokeAccess(DataObject dataObject, Host host, DataStore dataStore)
464481 throw new InvalidParameterValueException ("host should not be null" );
465482 }
466483
467- // Safety check: don't revoke access if volume is still attached to an active VM
468- if (dataObject .getType () == DataObjectType .VOLUME ) {
469- Volume volume = volumeDao .findById (dataObject .getId ());
470- if (volume .getInstanceId () != null ) {
471- VirtualMachine vm = vmDao .findById (volume .getInstanceId ());
472- if (vm != null && !Arrays .asList (
473- VirtualMachine .State .Destroyed ,
474- VirtualMachine .State .Expunging ,
475- VirtualMachine .State .Error ).contains (vm .getState ())) {
476- s_logger .warn ("revokeAccess: Volume [{}] is still attached to VM [{}] in state [{}], skipping revokeAccess" ,
477- dataObject .getId (), vm .getInstanceName (), vm .getState ());
478- return ;
479- }
480- }
481- }
482-
483484 StoragePoolVO storagePool = storagePoolDao .findById (dataStore .getId ());
484485 if (storagePool == null ) {
485486 s_logger .error ("revokeAccess: Storage Pool not found for id: " + dataStore .getId ());
@@ -517,10 +518,9 @@ private void revokeAccessForVolume(StoragePoolVO storagePool, VolumeVO volumeVO,
517518 Map <String , String > details = storagePoolDetailsDao .listDetailsKeyPairs (storagePool .getId ());
518519 StorageStrategy storageStrategy = Utility .getStrategyByStoragePoolDetails (details );
519520 String svmName = details .get (Constants .SVM_NAME );
520- String storagePoolUuid = storagePool .getUuid ();
521521
522522 if (ProtocolType .ISCSI .name ().equalsIgnoreCase (details .get (Constants .PROTOCOL ))) {
523- String accessGroupName = Utility .getIgroupName (svmName , storagePoolUuid );
523+ String accessGroupName = Utility .getIgroupName (svmName , host . getName () );
524524
525525 // Retrieve LUN name from volume details; if missing, volume may not have been fully created
526526 String lunName = volumeDetailsDao .findDetail (volumeVO .getId (), Constants .LUN_DOT_NAME ) != null ?
@@ -546,7 +546,7 @@ private void revokeAccessForVolume(StoragePoolVO storagePool, VolumeVO volumeVO,
546546
547547 // Verify host initiator is in the igroup before attempting to remove mapping
548548 SANStrategy sanStrategy = (UnifiedSANStrategy ) storageStrategy ;
549- if (!sanStrategy .validateInitiatorInAccessGroup (host .getStorageUrl (), svmName , accessGroup .getIgroup (). getName () )) {
549+ if (!sanStrategy .validateInitiatorInAccessGroup (host .getStorageUrl (), svmName , accessGroup .getIgroup ())) {
550550 s_logger .warn ("revokeAccessForVolume: Initiator [{}] is not in iGroup [{}], skipping revoke" ,
551551 host .getStorageUrl (), accessGroupName );
552552 return ;
@@ -915,7 +915,6 @@ public boolean isVmInfoNeeded() {
915915
916916 @ Override
917917 public void provideVmInfo (long vmId , long volumeId ) {
918-
919918 }
920919
921920 @ Override
0 commit comments