Skip to content

Commit eafc1e7

Browse files
Gupta, SuryaGupta, Surya
authored andcommitted
CSTACKEX-46 Create Async, Attach Cluster/Zone and Grant/Revoke Access
1 parent 1b0c7f7 commit eafc1e7

File tree

8 files changed

+484
-83
lines changed

8 files changed

+484
-83
lines changed

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

Lines changed: 161 additions & 33 deletions
Large diffs are not rendered by default.

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/client/SANFeignClient.java

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919
package org.apache.cloudstack.storage.feign.client;
2020

21+
import feign.QueryMap;
2122
import org.apache.cloudstack.storage.feign.model.Igroup;
2223
import org.apache.cloudstack.storage.feign.model.Lun;
2324
import org.apache.cloudstack.storage.feign.model.LunMap;
@@ -26,6 +27,7 @@
2627
import feign.Param;
2728
import feign.RequestLine;
2829
import java.net.URI;
30+
import java.util.Map;
2931

3032
//TODO: Proper URLs should be added in the RequestLine annotations below
3133
public interface SANFeignClient {
@@ -54,15 +56,14 @@ OntapResponse<Lun> createLun(@Param("authHeader") String authHeader,
5456
void deleteLun(@Param("authHeader") String authHeader, @Param("uuid") String uuid);
5557

5658
// iGroup Operation APIs
57-
@RequestLine("POST /")
59+
@RequestLine("POST /api/protocols/san/igroups")
5860
@Headers({"Authorization: {authHeader}", "return_records: {returnRecords}"})
5961
OntapResponse<Igroup> createIgroup(@Param("authHeader") String authHeader,
60-
@Param("returnRecords") boolean returnRecords,
61-
Igroup igroupRequest);
62+
@Param("returnRecords") boolean returnRecords, Igroup igroupRequest);
6263

63-
@RequestLine("GET /")
64-
@Headers({"Authorization: {authHeader}"}) // TODO: Check this again, uuid should be part of the path?
65-
OntapResponse<Igroup> getIgroupResponse(@Param("authHeader") String authHeader, @Param("uuid") String uuid);
64+
@RequestLine("GET /api/protocols/san/igroups")
65+
@Headers({"Authorization: {authHeader}"})
66+
OntapResponse<Igroup> getIgroupResponse(@Param("authHeader") String authHeader, @QueryMap Map<String, Object> queryMap);
6667

6768
@RequestLine("GET /{uuid}")
6869
@Headers({"Authorization: {authHeader}"})
@@ -73,17 +74,18 @@ OntapResponse<Igroup> createIgroup(@Param("authHeader") String authHeader,
7374
void deleteIgroup(@Param("baseUri") URI baseUri, @Param("authHeader") String authHeader, @Param("uuid") String uuid);
7475

7576
// LUN Maps Operation APIs
76-
@RequestLine("POST /")
77-
@Headers({"Authorization: {authHeader}"})
78-
OntapResponse<LunMap> createLunMap(@Param("authHeader") String authHeader, LunMap lunMap);
77+
@RequestLine("POST /api/protocols/san/lun-maps")
78+
@Headers({"Authorization: {authHeader}", "return_records: {returnRecords}"})
79+
OntapResponse<LunMap> createLunMap(@Param("authHeader") String authHeader, @Param("returnRecords") boolean returnRecords, LunMap lunMap);
80+
7981

8082
@RequestLine("GET /")
8183
@Headers({"Authorization: {authHeader}"})
8284
OntapResponse<LunMap> getLunMapResponse(@Param("authHeader") String authHeader);
8385

84-
@RequestLine("DELETE /{lunUuid}/{igroupUuid}")
86+
@RequestLine("DELETE /api/protocols/san/lun-maps/{lunUuid}/{igroupUuid}")
8587
@Headers({"Authorization: {authHeader}"})
8688
void deleteLunMap(@Param("authHeader") String authHeader,
87-
@Param("lunUuid") String lunUuid,
88-
@Param("igroupUuid") String igroupUuid);
89+
@Param("lunUuid") String lunUUID,
90+
@Param("igroupUuid") String igroupUUID);
8991
}

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/lifecycle/OntapPrimaryDatastoreLifecycle.java

Lines changed: 84 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.cloud.agent.api.StoragePoolInfo;
2424
import com.cloud.dc.ClusterVO;
2525
import com.cloud.dc.dao.ClusterDao;
26+
import com.cloud.exception.InvalidParameterValueException;
2627
import com.cloud.host.HostVO;
2728
import com.cloud.hypervisor.Hypervisor;
2829
import com.cloud.resource.ResourceManager;
@@ -38,17 +39,23 @@
3839
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle;
3940
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters;
4041
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
42+
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
43+
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
44+
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
4145
import org.apache.cloudstack.storage.datastore.lifecycle.BasePrimaryDataStoreLifeCycleImpl;
4246
import org.apache.cloudstack.storage.feign.model.OntapStorage;
4347
import org.apache.cloudstack.storage.provider.StorageProviderFactory;
4448
import org.apache.cloudstack.storage.service.StorageStrategy;
49+
import org.apache.cloudstack.storage.service.model.AccessGroup;
4550
import org.apache.cloudstack.storage.service.model.ProtocolType;
4651
import org.apache.cloudstack.storage.utils.Constants;
52+
import org.apache.cloudstack.storage.utils.Utility;
4753
import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
4854
import org.apache.logging.log4j.LogManager;
4955
import org.apache.logging.log4j.Logger;
5056

5157
import javax.inject.Inject;
58+
import java.util.ArrayList;
5259
import java.util.List;
5360
import java.util.Map;
5461
import java.util.Set;
@@ -59,6 +66,8 @@ public class OntapPrimaryDatastoreLifecycle extends BasePrimaryDataStoreLifeCycl
5966
@Inject private StorageManager _storageMgr;
6067
@Inject private ResourceManager _resourceMgr;
6168
@Inject private PrimaryDataStoreHelper _dataStoreHelper;
69+
@Inject private PrimaryDataStoreDao storagePoolDao;
70+
@Inject private StoragePoolDetailsDao storagePoolDetailsDao;
6271
private static final Logger s_logger = LogManager.getLogger(OntapPrimaryDatastoreLifecycle.class);
6372

6473
// ONTAP minimum volume size is 1.56 GB (1677721600 bytes)
@@ -241,16 +250,42 @@ public DataStore initialize(Map<String, Object> dsInfos) {
241250
@Override
242251
public boolean attachCluster(DataStore dataStore, ClusterScope scope) {
243252
logger.debug("In attachCluster for ONTAP primary storage");
244-
PrimaryDataStoreInfo primarystore = (PrimaryDataStoreInfo)dataStore;
245-
List<HostVO> hostsToConnect = _resourceMgr.getEligibleUpAndEnabledHostsInClusterForStorageConnection(primarystore);
253+
if (dataStore == null) {
254+
throw new InvalidParameterValueException("attachCluster: dataStore should not be null");
255+
}
256+
if (scope == null) {
257+
throw new InvalidParameterValueException("attachCluster: scope should not be null");
258+
}
259+
List<String> hostsIdentifier = new ArrayList<>();
260+
StoragePoolVO storagePool = storagePoolDao.findById(dataStore.getId());
261+
if(storagePool == null) {
262+
s_logger.error("attachCluster : Storage Pool not found for id: " + dataStore.getId());
263+
throw new CloudRuntimeException("attachCluster : Storage Pool not found for id: " + dataStore.getId());
264+
}
265+
PrimaryDataStoreInfo primaryStore = (PrimaryDataStoreInfo)dataStore;
266+
List<HostVO> hostsToConnect = _resourceMgr.getEligibleUpAndEnabledHostsInClusterForStorageConnection(primaryStore);
267+
// TODO- need to check if no host to connect then throw exception or just continue
268+
logger.debug("attachCluster: Eligible Up and Enabled hosts: {} in cluster {}", hostsToConnect, primaryStore.getClusterId());
246269

247-
logger.debug(String.format("Attaching the pool to each of the hosts %s in the cluster: %s", hostsToConnect, primarystore.getClusterId()));
270+
Map<String, String> details = primaryStore.getDetails();
271+
StorageStrategy strategy = Utility.getStrategyByStoragePoolDetails(details);
272+
ProtocolType protocol = ProtocolType.valueOf(details.get(Constants.PROTOCOL));
273+
//TODO- Check if we have to handle heterogeneous host within the cluster
274+
if (!isProtocolSupportedByAllHosts(hostsToConnect, protocol, hostsIdentifier)) {
275+
s_logger.error("attachCluster: Not all hosts in the cluster support the protocol: " + protocol.name());
276+
throw new CloudRuntimeException("attachCluster: Not all hosts in the cluster support the protocol: " + protocol.name());
277+
}
278+
//TODO - check if no host to connect then also need to create access group without initiators
279+
if (hostsIdentifier != null && hostsIdentifier.size() > 0) {
280+
AccessGroup accessGroupRequest = Utility.createAccessGroupRequestByProtocol(storagePool, scope.getScopeId(), details, hostsIdentifier);
281+
strategy.createAccessGroup(accessGroupRequest);
282+
}
283+
logger.debug("attachCluster: Attaching the pool to each of the host in the cluster: {}", primaryStore.getClusterId());
248284
for (HostVO host : hostsToConnect) {
249-
// TODO: Fetch the host IQN and add to the initiator group on ONTAP cluster
250285
try {
251286
_storageMgr.connectHostToSharedPool(host, dataStore.getId());
252287
} catch (Exception e) {
253-
logger.warn("Unable to establish a connection between " + host + " and " + dataStore, e);
288+
logger.warn("attachCluster: Unable to establish a connection between " + host + " and " + dataStore, e);
254289
}
255290
}
256291
_dataStoreHelper.attachCluster(dataStore);
@@ -265,11 +300,35 @@ public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo exis
265300
@Override
266301
public boolean attachZone(DataStore dataStore, ZoneScope scope, Hypervisor.HypervisorType hypervisorType) {
267302
logger.debug("In attachZone for ONTAP primary storage");
303+
if (dataStore == null) {
304+
throw new InvalidParameterValueException("attachZone: dataStore should not be null");
305+
}
306+
if (scope == null) {
307+
throw new InvalidParameterValueException("attachZone: scope should not be null");
308+
}
309+
List<String> hostsIdentifier = new ArrayList<>();
310+
StoragePoolVO storagePool = storagePoolDao.findById(dataStore.getId());
311+
if(storagePool == null) {
312+
s_logger.error("attachZone : Storage Pool not found for id: " + dataStore.getId());
313+
throw new CloudRuntimeException("attachZone : Storage Pool not found for id: " + dataStore.getId());
314+
}
268315
List<HostVO> hostsToConnect = _resourceMgr.getEligibleUpAndEnabledHostsInZoneForStorageConnection(dataStore, scope.getScopeId(), Hypervisor.HypervisorType.KVM);
316+
// TODO- need to check if no host to connect then throw exception or just continue
317+
logger.debug("attachZone: Eligible Up and Enabled hosts: {}", hostsToConnect);
269318

270-
logger.debug(String.format("In createPool. Attaching the pool to each of the hosts in %s.", hostsToConnect));
319+
Map<String, String> details = storagePoolDetailsDao.listDetailsKeyPairs(dataStore.getId());
320+
StorageStrategy strategy = Utility.getStrategyByStoragePoolDetails(details);
321+
ProtocolType protocol = ProtocolType.valueOf(details.get(Constants.PROTOCOL));
322+
//TODO- Check if we have to handle heterogeneous host within the zone
323+
if (!isProtocolSupportedByAllHosts(hostsToConnect, protocol, hostsIdentifier)) {
324+
s_logger.error("attachZone: Not all hosts in the cluster support the protocol: " + protocol.name());
325+
throw new CloudRuntimeException("attachZone: Not all hosts in the zone support the protocol: " + protocol.name());
326+
}
327+
if (hostsIdentifier != null && !hostsIdentifier.isEmpty()) {
328+
AccessGroup accessGroupRequest = Utility.createAccessGroupRequestByProtocol(storagePool, scope.getScopeId(), details, hostsIdentifier);
329+
strategy.createAccessGroup(accessGroupRequest);
330+
}
271331
for (HostVO host : hostsToConnect) {
272-
// TODO: Fetch the host IQN and add to the initiator group on ONTAP cluster
273332
try {
274333
_storageMgr.connectHostToSharedPool(host, dataStore.getId());
275334
} catch (Exception e) {
@@ -280,6 +339,24 @@ public boolean attachZone(DataStore dataStore, ZoneScope scope, Hypervisor.Hyper
280339
return true;
281340
}
282341

342+
private boolean isProtocolSupportedByAllHosts(List<HostVO> hosts, ProtocolType protocolType, List<String> hostIdentifiers) {
343+
switch (protocolType) {
344+
case ISCSI:
345+
String protocolPrefix = Constants.IQN;
346+
for (HostVO host : hosts) {
347+
if (host == null || host.getStorageUrl() == null || host.getStorageUrl().trim().isEmpty()
348+
|| !host.getStorageUrl().startsWith(protocolPrefix)) {
349+
return false;
350+
}
351+
hostIdentifiers.add(host.getStorageUrl());
352+
}
353+
break;
354+
default:
355+
throw new CloudRuntimeException("isProtocolSupportedByAllHosts : Unsupported protocol: " + protocolType.name());
356+
}
357+
return true;
358+
}
359+
283360
@Override
284361
public boolean maintain(DataStore store) {
285362
return true;

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/StorageStrategy.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -274,10 +274,10 @@ public Volume getStorageVolume(Volume volume)
274274
* getLun for iSCSI, FC protocols
275275
* getFile for NFS3.0 and NFS4.1 protocols
276276
* getNameSpace for Nvme/TCP and Nvme/FC protocol
277-
* @param cloudstackVolume the CloudStack volume to retrieve
277+
* @param cloudStackVolumeMap the CloudStack volume to retrieve
278278
* @return the retrieved CloudStackVolume object
279279
*/
280-
abstract CloudStackVolume getCloudStackVolume(CloudStackVolume cloudstackVolume);
280+
abstract public CloudStackVolume getCloudStackVolume(Map<String, String> cloudStackVolumeMap);
281281

282282
/**
283283
* Method encapsulates the behavior based on the opted protocol in subclasses
@@ -287,7 +287,7 @@ public Volume getStorageVolume(Volume volume)
287287
* @param accessGroup the access group to create
288288
* @return the created AccessGroup object
289289
*/
290-
abstract AccessGroup createAccessGroup(AccessGroup accessGroup);
290+
abstract public AccessGroup createAccessGroup(AccessGroup accessGroup);
291291

292292
/**
293293
* Method encapsulates the behavior based on the opted protocol in subclasses
@@ -310,27 +310,25 @@ public Volume getStorageVolume(Volume volume)
310310

311311
/**
312312
* Method encapsulates the behavior based on the opted protocol in subclasses
313-
* getiGroup for iSCSI and FC protocols
314-
* getExportPolicy for NFS 3.0 and NFS 4.1 protocols
315-
* getNameSpace for Nvme/TCP and Nvme/FC protocols
316-
* @param accessGroup the access group to retrieve
317-
* @return the retrieved AccessGroup object
313+
@@ -306,22 +306,22 @@ public Volume getStorageVolume(Volume volume)
314+
* getNameSpace for Nvme/TCP and Nvme/FC protocols
315+
* @param values
318316
*/
319-
abstract AccessGroup getAccessGroup(AccessGroup accessGroup);
317+
abstract public AccessGroup getAccessGroup(Map<String, String> values);
320318

321319
/**
322320
* Method encapsulates the behavior based on the opted protocol in subclasses
323321
* lunMap for iSCSI and FC protocols
324322
* //TODO for Nvme/TCP and Nvme/FC protocols
325323
* @param values
326324
*/
327-
abstract void enableLogicalAccess(Map<String,String> values);
325+
abstract public void enableLogicalAccess(Map<String,String> values);
328326

329327
/**
330328
* Method encapsulates the behavior based on the opted protocol in subclasses
331329
* lunUnmap for iSCSI and FC protocols
332330
* //TODO for Nvme/TCP and Nvme/FC protocols
333331
* @param values
334332
*/
335-
abstract void disableLogicalAccess(Map<String,String> values);
333+
abstract public void disableLogicalAccess(Map<String,String> values);
336334
}

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/service/UnifiedNASStrategy.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ void deleteCloudStackVolume(CloudStackVolume cloudstackVolume) {
6767
}
6868

6969
@Override
70-
CloudStackVolume getCloudStackVolume(CloudStackVolume cloudstackVolume) {
70+
public CloudStackVolume getCloudStackVolume(Map<String, String> cloudStackVolumeMap) {
7171
//TODO
7272
return null;
7373
}
@@ -90,18 +90,18 @@ public AccessGroup updateAccessGroup(AccessGroup accessGroup) {
9090
}
9191

9292
@Override
93-
public AccessGroup getAccessGroup(AccessGroup accessGroup) {
93+
public AccessGroup getAccessGroup(Map<String, String> values) {
9494
//TODO
9595
return null;
9696
}
9797

9898
@Override
99-
void enableLogicalAccess(Map<String, String> values) {
99+
public void enableLogicalAccess(Map<String, String> values) {
100100
//TODO
101101
}
102102

103103
@Override
104-
void disableLogicalAccess(Map<String, String> values) {
104+
public void disableLogicalAccess(Map<String, String> values) {
105105
//TODO
106106
}
107107
}

0 commit comments

Comments
 (0)