Skip to content

Commit 128787a

Browse files
Locharla, SandeepLocharla, Sandeep
authored andcommitted
CSTACKEX-25: Basic class structure
1 parent 033c23d commit 128787a

File tree

10 files changed

+286
-8
lines changed

10 files changed

+286
-8
lines changed

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

Lines changed: 122 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,39 @@
2121

2222

2323
import com.cloud.agent.api.StoragePoolInfo;
24+
import com.cloud.dc.ClusterVO;
25+
import com.cloud.dc.dao.ClusterDao;
26+
import com.cloud.host.HostVO;
2427
import com.cloud.hypervisor.Hypervisor;
28+
import com.cloud.resource.ResourceManager;
29+
import com.cloud.storage.Storage;
30+
import com.cloud.storage.StorageManager;
2531
import com.cloud.storage.StoragePool;
32+
import com.google.common.base.Preconditions;
2633
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
2734
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
2835
import org.apache.cloudstack.engine.subsystem.api.storage.HostScope;
36+
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo;
2937
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle;
38+
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters;
3039
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
40+
import org.apache.cloudstack.storage.datastore.lifecycle.BasePrimaryDataStoreLifeCycleImpl;
41+
import org.apache.cloudstack.storage.ontap.StorageProviderManager;
42+
import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
3143
import org.apache.logging.log4j.LogManager;
3244
import org.apache.logging.log4j.Logger;
33-
import java.util.Map;
3445

35-
public class OntapPrimaryDatastoreLifecycle implements PrimaryDataStoreLifeCycle {
46+
import javax.inject.Inject;
47+
import java.util.ArrayList;
48+
import java.util.List;
49+
import java.util.Map;
50+
import java.util.UUID;
3651

52+
public class OntapPrimaryDatastoreLifecycle extends BasePrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLifeCycle {
53+
@Inject private ClusterDao _clusterDao;
54+
@Inject private StorageManager _storageMgr;
55+
@Inject private ResourceManager _resourceMgr;
56+
@Inject private PrimaryDataStoreHelper _dataStoreHelper;
3757
private static final Logger s_logger = (Logger)LogManager.getLogger(OntapPrimaryDatastoreLifecycle.class);
3858

3959
/**
@@ -43,14 +63,91 @@ public class OntapPrimaryDatastoreLifecycle implements PrimaryDataStoreLifeCycle
4363
*/
4464
@Override
4565
public DataStore initialize(Map<String, Object> dsInfos) {
46-
47-
return null;
48-
66+
String url = (String) dsInfos.get("url");
67+
Long zoneId = (Long) dsInfos.get("zoneId");
68+
Long podId = (Long)dsInfos.get("podId");
69+
Long clusterId = (Long)dsInfos.get("clusterId");
70+
String storagePoolName = (String)dsInfos.get("name");
71+
String providerName = (String)dsInfos.get("providerName");
72+
String tags = (String)dsInfos.get("tags");
73+
Boolean isTagARule = (Boolean) dsInfos.get("isTagARule");
74+
String protocol = (String) dsInfos.get("protocol"); // TODO: Figure out the proper key for protocol
75+
// Additional details requested for ONTAP primary storage pool creation
76+
@SuppressWarnings("unchecked")
77+
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
78+
// Validations
79+
if (podId != null && clusterId == null) {
80+
s_logger.error("Cluster Id is null, cannot create primary storage");
81+
return null;
82+
} else if (podId == null && clusterId != null) {
83+
s_logger.error("Pod Id is null, cannot create primary storage");
84+
return null;
85+
}
86+
87+
if (podId == null && clusterId == null) {
88+
if (zoneId != null) {
89+
s_logger.info("Both Pod Id and Cluster Id are null, Primary storage pool will be associated with a Zone");
90+
} else {
91+
s_logger.error("Pod Id, Cluster Id and Zone Id are all null, cannot create primary storage");
92+
return null;
93+
}
94+
}
95+
96+
PrimaryDataStoreParameters parameters = new PrimaryDataStoreParameters();
97+
if (clusterId != null) {
98+
ClusterVO clusterVO = _clusterDao.findById(clusterId);
99+
Preconditions.checkNotNull(clusterVO, "Unable to locate the specified cluster");
100+
parameters.setHypervisorType(clusterVO.getHypervisorType());
101+
}
102+
else {
103+
parameters.setHypervisorType(Hypervisor.HypervisorType.Any);
104+
}
105+
106+
// Validate the ONTAP details
107+
StorageProviderManager storageProviderManager = new StorageProviderManager(details, protocol);
108+
boolean isValid = storageProviderManager.connect(details);
109+
//TODO: Use the return value to decide if we should proceed with pool creation
110+
111+
if (isValid) {
112+
String volumeName = storagePoolName + "_vol"; //TODO: Figure out a better naming convention
113+
storageProviderManager.createVolume(volumeName, Long.parseLong(details.get("size"))); // TODO: size should be in bytes, so see if conversion is needed
114+
// TODO: The volume name should be stored against the StoragePool name/id in the DB
115+
} else {
116+
s_logger.error("ONTAP details validation failed, cannot create primary storage");
117+
return null; // TODO: Figure out a better exception handling mechanism
118+
}
119+
120+
parameters.setTags(tags);
121+
parameters.setIsTagARule(isTagARule);
122+
parameters.setDetails(details);
123+
parameters.setType(Storage.StoragePoolType.Iscsi);
124+
parameters.setUuid(UUID.randomUUID().toString());
125+
parameters.setZoneId(zoneId);
126+
parameters.setPodId(podId);
127+
parameters.setClusterId(clusterId);
128+
parameters.setName(storagePoolName);
129+
parameters.setProviderName(providerName);
130+
parameters.setManaged(true);
131+
132+
return _dataStoreHelper.createPrimaryDataStore(parameters);
49133
}
50134

51135
@Override
52-
public boolean attachCluster(DataStore store, ClusterScope scope) {
53-
return false;
136+
public boolean attachCluster(DataStore dataStore, ClusterScope scope) {
137+
PrimaryDataStoreInfo primarystore = (PrimaryDataStoreInfo)dataStore;
138+
List<HostVO> hostsToConnect = _resourceMgr.getEligibleUpAndEnabledHostsInClusterForStorageConnection(primarystore);
139+
140+
logger.debug(String.format("Attaching the pool to each of the hosts %s in the cluster: %s", hostsToConnect, primarystore.getClusterId()));
141+
for (HostVO host : hostsToConnect) {
142+
// TODO: Fetch the host IQN and add to the initiator group on ONTAP cluster
143+
try {
144+
_storageMgr.connectHostToSharedPool(host, dataStore.getId());
145+
} catch (Exception e) {
146+
logger.warn("Unable to establish a connection between " + host + " and " + dataStore, e);
147+
}
148+
}
149+
_dataStoreHelper.attachCluster(dataStore);
150+
return true;
54151
}
55152

56153
@Override
@@ -60,7 +157,24 @@ public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo exis
60157

61158
@Override
62159
public boolean attachZone(DataStore dataStore, ZoneScope scope, Hypervisor.HypervisorType hypervisorType) {
63-
return false;
160+
List<HostVO> hostsToConnect = new ArrayList<>();
161+
Hypervisor.HypervisorType[] hypervisorTypes = {Hypervisor.HypervisorType.XenServer, Hypervisor.HypervisorType.VMware, Hypervisor.HypervisorType.KVM};
162+
163+
for (Hypervisor.HypervisorType type : hypervisorTypes) {
164+
hostsToConnect.addAll(_resourceMgr.getEligibleUpAndEnabledHostsInZoneForStorageConnection(dataStore, scope.getScopeId(), type));
165+
}
166+
167+
logger.debug(String.format("In createPool. Attaching the pool to each of the hosts in %s.", hostsToConnect));
168+
for (HostVO host : hostsToConnect) {
169+
// TODO: Fetch the host IQN and add to the initiator group on ONTAP cluster
170+
try {
171+
_storageMgr.connectHostToSharedPool(host, dataStore.getId());
172+
} catch (Exception e) {
173+
logger.warn("Unable to establish a connection between " + host + " and " + dataStore, e);
174+
}
175+
}
176+
_dataStoreHelper.attachZone(dataStore);
177+
return true;
64178
}
65179

66180
@Override
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package org.apache.cloudstack.storage.ontap;
2+
3+
import org.apache.cloudstack.storage.lifecycle.OntapPrimaryDatastoreLifecycle;
4+
import org.apache.cloudstack.storage.strategy.NASStrategy;
5+
import org.apache.cloudstack.storage.strategy.SANStrategy;
6+
import org.apache.cloudstack.storage.strategy.UnifiedNASStrategy;
7+
import org.apache.cloudstack.storage.strategy.UnifiedSANStrategy;
8+
import org.apache.logging.log4j.LogManager;
9+
import org.apache.logging.log4j.Logger;
10+
11+
import java.util.Map;
12+
13+
public class StorageProviderManager {
14+
private final NASStrategy nasStrategy;
15+
private final SANStrategy sanStrategy;
16+
private static final Logger s_logger = (Logger) LogManager.getLogger(StorageProviderManager.class);
17+
18+
public StorageProviderManager(Map<String, String> details, String protocol) {
19+
String svmName = details.get("svmName");
20+
String username = details.get("username");
21+
if ("nfs".equalsIgnoreCase(protocol)) { // TODO: Cloudstack protocol list is different than ONTAP supported protocols, so figure out the proper mapping
22+
this.nasStrategy = new UnifiedNASStrategy(details);
23+
this.sanStrategy = null;
24+
} else if ("iscsi".equalsIgnoreCase(protocol)) { // TODO: Cloudstack protocol list is different than ONTAP supported protocols, so figure out the proper mapping
25+
this.sanStrategy = new UnifiedSANStrategy(details);
26+
this.nasStrategy = null;
27+
} else {
28+
//TODO: Figure out the appropriate exception handling mechanism
29+
this.nasStrategy = null;
30+
this.sanStrategy = null;
31+
s_logger.error("Unsupported protocol: " + protocol);
32+
return;
33+
}
34+
}
35+
36+
// Connect method to validate ONTAP cluster, credentials, protocol, and SVM
37+
public boolean connect(Map<String, String> details) {
38+
// 1. Check if ONTAP cluster is reachable
39+
// 2. Validate credentials
40+
// 3. Check protocol support
41+
// 4. Check if SVM with given name exists
42+
// Use Feign client and models for actual implementation
43+
// Return true if all validations pass, false otherwise
44+
45+
return false;
46+
}
47+
48+
// Common methods like create/delete etc., should be here
49+
public void createVolume(String volumeName, long size) {
50+
// TODO: Call the ontap feign client for creating volume here
51+
}
52+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//package org.apache.cloudstack.storage.ontap.clients;
2+
//
3+
//import org.apache.cloudstack.storage.ontap.models.CreateVolumeRequest;
4+
//import org.apache.cloudstack.storage.ontap.models.CreateVolumeResponse;
5+
//import feign.RequestLine;
6+
//import feign.Body;
7+
//
8+
//public interface OntapFeignClient {
9+
// @RequestLine("POST /api/storage/volumes")
10+
// @Body("{body}")
11+
// CreateVolumeResponse createVolume(CreateVolumeRequest body);
12+
//}
13+
//
14+
//
15+
//
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//package org.apache.cloudstack.storage.ontap.models;
2+
//
3+
//public class CreateVolumeRequest {
4+
// private String volumeName;
5+
// private long size;
6+
// // getters and setters
7+
//}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//package org.apache.cloudstack.storage.ontap.models;
2+
//
3+
//public class CreateVolumeResponse {
4+
// private String status;
5+
// private String volumeId;
6+
// // getters and setters
7+
//}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.apache.cloudstack.storage.strategy;
2+
3+
public interface NASStrategy {
4+
String createExportPolicy(String svmName, String policyName);
5+
String addExportRule(String policyName, String clientMatch, String[] protocols, String[] roRule, String[] rwRule);
6+
String assignExportPolicyToVolume(String volumeUuid, String policyName);
7+
String enableNFS(String svmUuid);
8+
}
9+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.apache.cloudstack.storage.strategy;
2+
3+
public interface SANStrategy {
4+
String createLUN(String svmName, String volumeName, String lunName, long sizeBytes, String osType);
5+
String createIgroup(String svmName, String igroupName, String[] initiators);
6+
String mapLUNToIgroup(String lunName, String igroupName);
7+
String enableISCSI(String svmUuid);
8+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.apache.cloudstack.storage.strategy;
2+
3+
import java.util.Map;
4+
5+
public class UnifiedNASStrategy implements NASStrategy{
6+
public UnifiedNASStrategy(Map<String, String> details) {
7+
}
8+
9+
@Override
10+
public String createExportPolicy(String svmName, String policyName) {
11+
return "";
12+
}
13+
14+
@Override
15+
public String addExportRule(String policyName, String clientMatch, String[] protocols, String[] roRule, String[] rwRule) {
16+
return "";
17+
}
18+
19+
@Override
20+
public String assignExportPolicyToVolume(String volumeUuid, String policyName) {
21+
return "";
22+
}
23+
24+
@Override
25+
public String enableNFS(String svmUuid) {
26+
return "";
27+
}
28+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.apache.cloudstack.storage.strategy;
2+
3+
import java.util.Map;
4+
5+
public class UnifiedSANStrategy implements SANStrategy{
6+
public UnifiedSANStrategy(Map<String, String> details) {
7+
8+
}
9+
10+
@Override
11+
public String createLUN(String svmName, String volumeName, String lunName, long sizeBytes, String osType) {
12+
return "";
13+
}
14+
15+
@Override
16+
public String createIgroup(String svmName, String igroupName, String[] initiators) {
17+
return "";
18+
}
19+
20+
@Override
21+
public String mapLUNToIgroup(String lunName, String igroupName) {
22+
return "";
23+
}
24+
25+
@Override
26+
public String enableISCSI(String svmUuid) {
27+
return "";
28+
}
29+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
openapi: 3.0.3
2+
info:
3+
title: Title
4+
description: Title
5+
version: 1.0.0
6+
servers:
7+
- url: 'https'
8+
paths:
9+

0 commit comments

Comments
 (0)