Skip to content

Commit ea40967

Browse files
piyush5netappSrivastava, Piyush
andauthored
feature/CSTACKEX-122: Per host Igroup changes (#37)
Co-authored-by: Srivastava, Piyush <Piyush.Srivastava@netapp.com>
1 parent fccaf83 commit ea40967

File tree

13 files changed

+470
-523
lines changed

13 files changed

+470
-523
lines changed

engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,15 @@ private void createManagedVolumeCopyTemplateAsync(VolumeInfo volumeInfo, Primary
13371337
primaryDataStore.setDetails(details);
13381338

13391339
grantAccess(volumeInfo, destHost, primaryDataStore);
1340+
volumeInfo = volFactory.getVolume(volumeInfo.getId(), primaryDataStore);
1341+
// For Netapp ONTAP iscsiName or Lun path is available only after grantAccess
1342+
String managedStoreTarget = volumeInfo.get_iScsiName() != null ? volumeInfo.get_iScsiName() : volumeInfo.getUuid();
1343+
details.put(PrimaryDataStore.MANAGED_STORE_TARGET, managedStoreTarget);
1344+
primaryDataStore.setDetails(details);
1345+
// Update destTemplateInfo with the iSCSI path from volumeInfo
1346+
if (destTemplateInfo instanceof TemplateObject) {
1347+
((TemplateObject)destTemplateInfo).setInstallPath(volumeInfo.getPath());
1348+
}
13401349

13411350
try {
13421351
motionSrv.copyAsync(srcTemplateInfo, destTemplateInfo, destHost, caller);

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java

Lines changed: 45 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.cloud.agent.api.to.DataTO;
2525
import com.cloud.exception.InvalidParameterValueException;
2626
import com.cloud.host.Host;
27+
import com.cloud.host.HostVO;
2728
import com.cloud.storage.Storage;
2829
import com.cloud.storage.StoragePool;
2930
import com.cloud.storage.Volume;
@@ -35,8 +36,6 @@
3536
import com.cloud.storage.dao.VolumeDetailsDao;
3637
import com.cloud.utils.Pair;
3738
import com.cloud.utils.exception.CloudRuntimeException;
38-
import com.cloud.vm.VirtualMachine;
39-
import com.cloud.vm.dao.VMInstanceDao;
4039
import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
4140
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
4241
import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
@@ -53,6 +52,7 @@
5352
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
5453
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
5554
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
55+
import org.apache.cloudstack.storage.feign.model.Igroup;
5656
import org.apache.cloudstack.storage.feign.client.SnapshotFeignClient;
5757
import org.apache.cloudstack.storage.feign.model.FlexVolSnapshot;
5858
import org.apache.cloudstack.storage.feign.model.Lun;
@@ -72,8 +72,9 @@
7272
import org.apache.logging.log4j.Logger;
7373

7474
import javax.inject.Inject;
75-
import java.util.Arrays;
75+
import java.util.ArrayList;
7676
import java.util.HashMap;
77+
import java.util.List;
7778
import 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

Comments
 (0)