Skip to content

Commit 994aac7

Browse files
Locharla, SandeepLocharla, Sandeep
authored andcommitted
CSTACKEX-25: Basic class structure
1 parent 4c8c8d9 commit 994aac7

File tree

11 files changed

+315
-8
lines changed

11 files changed

+315
-8
lines changed

plugins/storage/volume/ontap/pom.xml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,35 @@
4646
</dependencies>
4747
<build>
4848
<plugins>
49+
<plugin>
50+
<groupId>org.openapitools</groupId>
51+
<artifactId>openapi-generator-maven-plugin</artifactId>
52+
<version>4.3.1</version>
53+
<executions>
54+
<execution>
55+
<goals>
56+
<goal>generate</goal>
57+
</goals>
58+
<configuration>
59+
<inputSpec>
60+
${project.basedir}/src/main/resources/openapi-v1.yaml
61+
</inputSpec>
62+
<generatorName>spring</generatorName>
63+
<apiPackage>org.apache.cloudstack.storage.ontap.clients</apiPackage>
64+
<modelPackage>org.apache.cloudstack.storage.ontap.models</modelPackage>
65+
<generateModels>true</generateModels>
66+
<generateModelTests>false</generateModelTests>
67+
<generateApis>true</generateApis>
68+
<generateApiTests>false</generateApiTests>
69+
<configOptions>
70+
<unhandledException>true</unhandledException>
71+
<useTags>true</useTags>
72+
<interfaceOnly>true</interfaceOnly>
73+
</configOptions>
74+
</configuration>
75+
</execution>
76+
</executions>
77+
</plugin>
4978
<plugin>
5079
<artifactId>maven-surefire-plugin</artifactId>
5180
<configuration>

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
@@ -2,19 +2,39 @@
22

33

44
import com.cloud.agent.api.StoragePoolInfo;
5+
import com.cloud.dc.ClusterVO;
6+
import com.cloud.dc.dao.ClusterDao;
7+
import com.cloud.host.HostVO;
58
import com.cloud.hypervisor.Hypervisor;
9+
import com.cloud.resource.ResourceManager;
10+
import com.cloud.storage.Storage;
11+
import com.cloud.storage.StorageManager;
612
import com.cloud.storage.StoragePool;
13+
import com.google.common.base.Preconditions;
714
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
815
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
916
import org.apache.cloudstack.engine.subsystem.api.storage.HostScope;
17+
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo;
1018
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle;
19+
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters;
1120
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
21+
import org.apache.cloudstack.storage.datastore.lifecycle.BasePrimaryDataStoreLifeCycleImpl;
22+
import org.apache.cloudstack.storage.ontap.StorageProviderManager;
23+
import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
1224
import org.apache.logging.log4j.LogManager;
1325
import org.apache.logging.log4j.Logger;
14-
import java.util.Map;
1526

16-
public class OntapPrimaryDatastoreLifecycle implements PrimaryDataStoreLifeCycle {
27+
import javax.inject.Inject;
28+
import java.util.ArrayList;
29+
import java.util.List;
30+
import java.util.Map;
31+
import java.util.UUID;
1732

33+
public class OntapPrimaryDatastoreLifecycle extends BasePrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLifeCycle {
34+
@Inject private ClusterDao _clusterDao;
35+
@Inject private StorageManager _storageMgr;
36+
@Inject private ResourceManager _resourceMgr;
37+
@Inject private PrimaryDataStoreHelper _dataStoreHelper;
1838
private static final Logger s_logger = (Logger)LogManager.getLogger(OntapPrimaryDatastoreLifecycle.class);
1939

2040
/**
@@ -24,14 +44,91 @@ public class OntapPrimaryDatastoreLifecycle implements PrimaryDataStoreLifeCycle
2444
*/
2545
@Override
2646
public DataStore initialize(Map<String, Object> dsInfos) {
27-
28-
return null;
29-
47+
String url = (String) dsInfos.get("url");
48+
Long zoneId = (Long) dsInfos.get("zoneId");
49+
Long podId = (Long)dsInfos.get("podId");
50+
Long clusterId = (Long)dsInfos.get("clusterId");
51+
String storagePoolName = (String)dsInfos.get("name");
52+
String providerName = (String)dsInfos.get("providerName");
53+
String tags = (String)dsInfos.get("tags");
54+
Boolean isTagARule = (Boolean) dsInfos.get("isTagARule");
55+
String protocol = (String) dsInfos.get("protocol"); // TODO: Figure out the proper key for protocol
56+
// Additional details requested for ONTAP primary storage pool creation
57+
@SuppressWarnings("unchecked")
58+
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
59+
// Validations
60+
if (podId != null && clusterId == null) {
61+
s_logger.error("Cluster Id is null, cannot create primary storage");
62+
return null;
63+
} else if (podId == null && clusterId != null) {
64+
s_logger.error("Pod Id is null, cannot create primary storage");
65+
return null;
66+
}
67+
68+
if (podId == null && clusterId == null) {
69+
if (zoneId != null) {
70+
s_logger.info("Both Pod Id and Cluster Id are null, Primary storage pool will be associated with a Zone");
71+
} else {
72+
s_logger.error("Pod Id, Cluster Id and Zone Id are all null, cannot create primary storage");
73+
return null;
74+
}
75+
}
76+
77+
PrimaryDataStoreParameters parameters = new PrimaryDataStoreParameters();
78+
if (clusterId != null) {
79+
ClusterVO clusterVO = _clusterDao.findById(clusterId);
80+
Preconditions.checkNotNull(clusterVO, "Unable to locate the specified cluster");
81+
parameters.setHypervisorType(clusterVO.getHypervisorType());
82+
}
83+
else {
84+
parameters.setHypervisorType(Hypervisor.HypervisorType.Any);
85+
}
86+
87+
// Validate the ONTAP details
88+
StorageProviderManager storageProviderManager = new StorageProviderManager(details, protocol);
89+
boolean isValid = storageProviderManager.connect(details);
90+
//TODO: Use the return value to decide if we should proceed with pool creation
91+
92+
if (isValid) {
93+
String volumeName = storagePoolName + "_vol"; //TODO: Figure out a better naming convention
94+
storageProviderManager.createVolume(volumeName, Long.parseLong(details.get("size"))); // TODO: size should be in bytes, so see if conversion is needed
95+
// TODO: The volume name should be stored against the StoragePool name/id in the DB
96+
} else {
97+
s_logger.error("ONTAP details validation failed, cannot create primary storage");
98+
return null; // TODO: Figure out a better exception handling mechanism
99+
}
100+
101+
parameters.setTags(tags);
102+
parameters.setIsTagARule(isTagARule);
103+
parameters.setDetails(details);
104+
parameters.setType(Storage.StoragePoolType.Iscsi);
105+
parameters.setUuid(UUID.randomUUID().toString());
106+
parameters.setZoneId(zoneId);
107+
parameters.setPodId(podId);
108+
parameters.setClusterId(clusterId);
109+
parameters.setName(storagePoolName);
110+
parameters.setProviderName(providerName);
111+
parameters.setManaged(true);
112+
113+
return _dataStoreHelper.createPrimaryDataStore(parameters);
30114
}
31115

32116
@Override
33-
public boolean attachCluster(DataStore store, ClusterScope scope) {
34-
return false;
117+
public boolean attachCluster(DataStore dataStore, ClusterScope scope) {
118+
PrimaryDataStoreInfo primarystore = (PrimaryDataStoreInfo)dataStore;
119+
List<HostVO> hostsToConnect = _resourceMgr.getEligibleUpAndEnabledHostsInClusterForStorageConnection(primarystore);
120+
121+
logger.debug(String.format("Attaching the pool to each of the hosts %s in the cluster: %s", hostsToConnect, primarystore.getClusterId()));
122+
for (HostVO host : hostsToConnect) {
123+
// TODO: Fetch the host IQN and add to the initiator group on ONTAP cluster
124+
try {
125+
_storageMgr.connectHostToSharedPool(host, dataStore.getId());
126+
} catch (Exception e) {
127+
logger.warn("Unable to establish a connection between " + host + " and " + dataStore, e);
128+
}
129+
}
130+
_dataStoreHelper.attachCluster(dataStore);
131+
return true;
35132
}
36133

37134
@Override
@@ -41,7 +138,24 @@ public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo exis
41138

42139
@Override
43140
public boolean attachZone(DataStore dataStore, ZoneScope scope, Hypervisor.HypervisorType hypervisorType) {
44-
return false;
141+
List<HostVO> hostsToConnect = new ArrayList<>();
142+
Hypervisor.HypervisorType[] hypervisorTypes = {Hypervisor.HypervisorType.XenServer, Hypervisor.HypervisorType.VMware, Hypervisor.HypervisorType.KVM};
143+
144+
for (Hypervisor.HypervisorType type : hypervisorTypes) {
145+
hostsToConnect.addAll(_resourceMgr.getEligibleUpAndEnabledHostsInZoneForStorageConnection(dataStore, scope.getScopeId(), type));
146+
}
147+
148+
logger.debug(String.format("In createPool. Attaching the pool to each of the hosts in %s.", hostsToConnect));
149+
for (HostVO host : hostsToConnect) {
150+
// TODO: Fetch the host IQN and add to the initiator group on ONTAP cluster
151+
try {
152+
_storageMgr.connectHostToSharedPool(host, dataStore.getId());
153+
} catch (Exception e) {
154+
logger.warn("Unable to establish a connection between " + host + " and " + dataStore, e);
155+
}
156+
}
157+
_dataStoreHelper.attachZone(dataStore);
158+
return true;
45159
}
46160

47161
@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+
}

0 commit comments

Comments
 (0)