Skip to content

Commit 572a1d5

Browse files
Locharla, SandeepLocharla, Sandeep
authored andcommitted
CSTACKEX-25: Basic class structure
Add PrimaryStoragePool base code CSTACKEX-25: Create Volume code basic code added CSTACKEX-25: additional logic for Primary storage pool creation CSTACKEX-29 Cluster, SVM and Aggr Feign Client CSTACKEX-29 Added License Info CSTACKEX-29 Resolve Review Comments CSTACKEX-29 Resolve Style check issues � This is the commit message #9: CSTACKEX-29 Resolve Style check issues � This is the commit message #10: CSTACKEX-29 Resolve Precommits Issues CSTACKEX-29 Resolve Precommits Issues CSTACKEX-25: PrimaryStoragePool create workflow almost done CSTACKEX-25: PrimaryStoragePool create workflow almost done CSTACKEX-25: Added license string to new file
1 parent a20dc4e commit 572a1d5

File tree

11 files changed

+340
-121
lines changed

11 files changed

+340
-121
lines changed

plugins/storage/volume/ontap/pom.xml

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
</parent>
3030
<properties>
3131
<spring-cloud.version>2021.0.7</spring-cloud.version>
32-
<spring-boot.version>2.7.10</spring-boot.version>
3332
<openfeign.version>11.0</openfeign.version>
3433
<json.version>20230227</json.version>
3534
<swagger-annotations.version>1.6.2</swagger-annotations.version>
@@ -87,15 +86,6 @@
8786
<artifactId>swagger-annotations</artifactId>
8887
<version>${swagger-annotations.version}</version>
8988
</dependency>
90-
<!-- <dependency>-->
91-
<!-- <groupId>org.springframework</groupId>-->
92-
<!-- <artifactId>spring-web</artifactId>-->
93-
<!-- </dependency>-->
94-
<!-- <dependency>-->
95-
<!-- <groupId>org.springframework.boot</groupId>-->
96-
<!-- <artifactId>spring-boot-starter</artifactId>-->
97-
<!-- <version>${spring-boot.version}</version>-->
98-
<!-- </dependency>-->
9989
</dependencies>
10090
<build>
10191
<plugins>

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/model/response/OntapResponse.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,3 @@ public void setRecords(List<T> records) {
6060
this.numRecords = (records != null) ? records.size() : 0;
6161
}
6262
}
63-
64-

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

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@
3939
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters;
4040
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
4141
import org.apache.cloudstack.storage.datastore.lifecycle.BasePrimaryDataStoreLifeCycleImpl;
42+
import org.apache.cloudstack.storage.model.OntapStorage;
4243
import org.apache.cloudstack.storage.provider.StorageProviderManager;
44+
import org.apache.cloudstack.storage.service.StorageStrategy;
45+
import org.apache.cloudstack.storage.utils.Constants;
4346
import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
4447
import org.apache.logging.log4j.LogManager;
4548
import org.apache.logging.log4j.Logger;
@@ -64,7 +67,10 @@ public class OntapPrimaryDatastoreLifecycle extends BasePrimaryDataStoreLifeCycl
6467
*/
6568
@Override
6669
public DataStore initialize(Map<String, Object> dsInfos) {
67-
String url = dsInfos.get("url").toString();
70+
if (dsInfos == null) {
71+
throw new CloudRuntimeException("Datastore info map is null, cannot create primary storage");
72+
}
73+
String url = dsInfos.get("url").toString(); // TODO: Decide on whether should the customer enter just the Management LIF IP or https://ManagementLIF
6874
Long zoneId = (Long) dsInfos.get("zoneId");
6975
Long podId = (Long)dsInfos.get("podId");
7076
Long clusterId = (Long)dsInfos.get("clusterId");
@@ -74,6 +80,9 @@ public DataStore initialize(Map<String, Object> dsInfos) {
7480
Boolean isTagARule = (Boolean) dsInfos.get("isTagARule");
7581
String scheme = dsInfos.get("scheme").toString();
7682

83+
s_logger.info("Creating ONTAP primary storage pool with name: " + storagePoolName + ", provider: " + providerName +
84+
", zoneId: " + zoneId + ", podId: " + podId + ", clusterId: " + clusterId + ", protocol: " + scheme);
85+
7786
// Additional details requested for ONTAP primary storage pool creation
7887
@SuppressWarnings("unchecked")
7988
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
@@ -94,6 +103,14 @@ public DataStore initialize(Map<String, Object> dsInfos) {
94103
}
95104
}
96105

106+
if (storagePoolName == null || storagePoolName.isEmpty()) {
107+
throw new CloudRuntimeException("Storage pool name is null or empty, cannot create primary storage");
108+
}
109+
110+
if (providerName == null || providerName.isEmpty()) {
111+
throw new CloudRuntimeException("Provider name is null or empty, cannot create primary storage");
112+
}
113+
97114
PrimaryDataStoreParameters parameters = new PrimaryDataStoreParameters();
98115
if (clusterId != null) {
99116
ClusterVO clusterVO = _clusterDao.findById(clusterId);
@@ -103,24 +120,31 @@ public DataStore initialize(Map<String, Object> dsInfos) {
103120
}
104121
parameters.setHypervisorType(clusterVO.getHypervisorType());
105122
}
106-
// Validate the ONTAP details
107-
StorageProviderManager storageProviderManager = new StorageProviderManager(details, scheme);
108-
boolean isValid = storageProviderManager.connect(details);
109-
if (isValid) {
110-
// String volumeName = storagePoolName + "_vol"; //TODO: Figure out a better naming convention
111-
storageProviderManager.createVolume(storagePoolName, Integer.parseInt((details.get("size")))); // TODO: size should be in bytes, so see if conversion is needed
112-
} else {
113-
throw new CloudRuntimeException("ONTAP details validation failed, cannot create primary storage");
114-
}
115123

116124
// TODO: While testing need to check what does this actually do and if the fields corresponding to each protocol should also be set
117-
if (scheme.equalsIgnoreCase("nfs")) {
125+
// TODO: scheme could be 'custom' in our case and we might have to ask 'protocol' separately to the user
126+
if (scheme.equalsIgnoreCase(Constants.NFS)) {
118127
parameters.setType(Storage.StoragePoolType.NetworkFilesystem);
119-
} else if (scheme.equalsIgnoreCase("iscsi")) {
128+
} else if (scheme.equalsIgnoreCase(Constants.ISCSI)) {
120129
parameters.setType(Storage.StoragePoolType.Iscsi);
121130
} else {
122131
throw new CloudRuntimeException("Unsupported protocol: " + scheme + ", cannot create primary storage");
123132
}
133+
details.put(Constants.MANAGEMENTLIF, url);
134+
// details.put(Constants.PROTOCOL, scheme);
135+
136+
// Validate the ONTAP details
137+
OntapStorage ontapStorage = new OntapStorage(details.get(Constants.USERNAME), details.get(Constants.PASSWORD),
138+
details.get(Constants.MANAGEMENTLIF), details.get(Constants.SVMNAME), scheme); //TODO: Here the passing 'scheme' might need a re-look
139+
StorageProviderManager storageProviderManager = new StorageProviderManager(ontapStorage);
140+
StorageStrategy storageStrategy = storageProviderManager.getStrategy();
141+
boolean isValid = storageStrategy.connect();
142+
if (isValid) {
143+
// String volumeName = storagePoolName + "_vol"; //TODO: Figure out a better naming convention
144+
storageStrategy.createVolume(storagePoolName, Long.parseLong((details.get("size")))); // TODO: size should be in bytes, so see if conversion is needed
145+
} else {
146+
throw new CloudRuntimeException("ONTAP details validation failed, cannot create primary storage");
147+
}
124148

125149
parameters.setTags(tags);
126150
parameters.setIsTagARule(isTagARule);
@@ -138,6 +162,7 @@ public DataStore initialize(Map<String, Object> dsInfos) {
138162

139163
@Override
140164
public boolean attachCluster(DataStore dataStore, ClusterScope scope) {
165+
logger.debug("In attachCluster for ONTAP primary storage");
141166
PrimaryDataStoreInfo primarystore = (PrimaryDataStoreInfo)dataStore;
142167
List<HostVO> hostsToConnect = _resourceMgr.getEligibleUpAndEnabledHostsInClusterForStorageConnection(primarystore);
143168

@@ -161,12 +186,8 @@ public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo exis
161186

162187
@Override
163188
public boolean attachZone(DataStore dataStore, ZoneScope scope, Hypervisor.HypervisorType hypervisorType) {
164-
List<HostVO> hostsToConnect = new ArrayList<>();
165-
Hypervisor.HypervisorType[] hypervisorTypes = {Hypervisor.HypervisorType.XenServer, Hypervisor.HypervisorType.VMware, Hypervisor.HypervisorType.KVM};
166-
167-
for (Hypervisor.HypervisorType type : hypervisorTypes) {
168-
hostsToConnect.addAll(_resourceMgr.getEligibleUpAndEnabledHostsInZoneForStorageConnection(dataStore, scope.getScopeId(), type));
169-
}
189+
logger.debug("In attachZone for ONTAP primary storage");
190+
List<HostVO> hostsToConnect = _resourceMgr.getEligibleUpAndEnabledHostsInZoneForStorageConnection(dataStore, scope.getScopeId(), Hypervisor.HypervisorType.KVM);
170191

171192
logger.debug(String.format("In createPool. Attaching the pool to each of the hosts in %s.", hostsToConnect));
172193
for (HostVO host : hostsToConnect) {
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.cloudstack.storage.model;
21+
22+
public class OntapStorage {
23+
public static String Username;
24+
public static String Password;
25+
public static String ManagementLIF;
26+
public static String SVM;
27+
public static String Protocol;
28+
29+
public OntapStorage(String username, String password, String managementLIF, String SVM, String protocol) {
30+
Username = username;
31+
Password = password;
32+
ManagementLIF = managementLIF;
33+
OntapStorage.SVM = SVM;
34+
Protocol = protocol;
35+
}
36+
37+
public String getUsername() {
38+
return Username;
39+
}
40+
41+
public void setUsername(String username) {
42+
Username = username;
43+
}
44+
45+
public String getPassword() {
46+
return Password;
47+
}
48+
49+
public void setPassword(String password) {
50+
Password = password;
51+
}
52+
53+
public String getManagementLIF() {
54+
return ManagementLIF;
55+
}
56+
57+
public void setManagementLIF(String managementLIF) {
58+
ManagementLIF = managementLIF;
59+
}
60+
61+
public String getSVM() {
62+
return SVM;
63+
}
64+
65+
public void setSVM(String SVM) {
66+
this.SVM = SVM;
67+
}
68+
69+
public String getProtocol() {
70+
return Protocol;
71+
}
72+
73+
public void setProtocol(String protocol) {
74+
Protocol = protocol;
75+
}
76+
}

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/provider/StorageProviderManager.java

Lines changed: 14 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -19,98 +19,36 @@
1919

2020
package org.apache.cloudstack.storage.provider;
2121

22-
import com.cloud.storage.Storage;
2322
import com.cloud.utils.exception.CloudRuntimeException;
24-
import org.apache.cloudstack.storage.feign.client.VolumeFeignClient;
25-
import org.apache.cloudstack.storage.feign.model.Svm;
26-
import org.apache.cloudstack.storage.feign.model.request.VolumeRequestDTO;
27-
import org.apache.cloudstack.storage.feign.model.response.JobResponseDTO;
28-
import org.apache.cloudstack.storage.service.NASStrategy;
29-
import org.apache.cloudstack.storage.service.SANStrategy;
23+
import org.apache.cloudstack.storage.model.OntapStorage;
24+
import org.apache.cloudstack.storage.service.StorageStrategy;
3025
import org.apache.cloudstack.storage.service.UnifiedNASStrategy;
3126
import org.apache.cloudstack.storage.service.UnifiedSANStrategy;
32-
import org.apache.cloudstack.storage.utils.Utility;
27+
import org.apache.cloudstack.storage.utils.Constants;
3328
import org.apache.logging.log4j.LogManager;
3429
import org.apache.logging.log4j.Logger;
35-
import org.springframework.beans.factory.annotation.Autowired;
3630
import org.springframework.stereotype.Component;
3731

38-
import java.util.List;
39-
import java.util.Map;
40-
4132
@Component
4233
public class StorageProviderManager {
43-
@Autowired
44-
private Utility utils;
45-
46-
@Autowired
47-
private VolumeFeignClient volumeFeignClient;
48-
49-
private final NASStrategy nasStrategy;
50-
private final SANStrategy sanStrategy;
34+
private final StorageStrategy storageStrategy;
5135
private static final Logger s_logger = (Logger) LogManager.getLogger(StorageProviderManager.class);
5236

53-
private final String username;
54-
private final String password;
55-
private final String svmName;
56-
private final String aggrName;
57-
58-
public StorageProviderManager(Map<String, String> details, String protocol) {
59-
this.svmName = details.get("svmName");
60-
this.aggrName = details.get("aggrName");
61-
this.username = details.get("username");
62-
this.password = details.get("password");
63-
if (protocol.equalsIgnoreCase(Storage.StoragePoolType.NetworkFilesystem.name())) {
64-
this.nasStrategy = new UnifiedNASStrategy(details);
65-
this.sanStrategy = null;
66-
} else if (protocol.equalsIgnoreCase(Storage.StoragePoolType.Iscsi.name())) {
67-
this.sanStrategy = new UnifiedSANStrategy(details);
68-
this.nasStrategy = null;
37+
public StorageProviderManager(OntapStorage ontapStorage) {
38+
String protocol = ontapStorage.getProtocol();
39+
s_logger.info("Initializing StorageProviderManager with protocol: " + protocol);
40+
if (protocol.equalsIgnoreCase(Constants.NFS)) {
41+
this.storageStrategy = new UnifiedNASStrategy(ontapStorage);
42+
} else if (protocol.equalsIgnoreCase(Constants.ISCSI)) {
43+
this.storageStrategy = new UnifiedSANStrategy(ontapStorage);
6944
} else {
70-
this.nasStrategy = null;
71-
this.sanStrategy = null;
45+
this.storageStrategy = null;
7246
throw new CloudRuntimeException("Unsupported protocol: " + protocol);
7347
}
74-
}
7548

76-
// Connect method to validate ONTAP cluster, credentials, protocol, and SVM
77-
public boolean connect(Map<String, String> details) {
78-
// 1. Check if ONTAP cluster is reachable ==> Use GET cluster API
79-
// 2. Validate credentials
80-
// 3. Check protocol support
81-
// 4. Check if SVM with given name exists
82-
// Use Feign client and models for actual implementation
83-
// Return true if all validations pass, false otherwise
84-
85-
return false;
8649
}
8750

88-
// Common methods like create/delete etc., should be here
89-
public void createVolume(String volumeName, int size) {
90-
// TODO: Call the ontap feign client for creating volume here
91-
// Get the AuthHeader
92-
String authHeader = utils.generateAuthHeader(username, password);
93-
94-
// Generate the Create Volume Request
95-
VolumeRequestDTO volumeRequest = new VolumeRequestDTO();
96-
VolumeRequestDTO.SvmDTO svm = new VolumeRequestDTO.SvmDTO();
97-
VolumeRequestDTO.AggregateDTO aggr = new VolumeRequestDTO.AggregateDTO();
98-
svm.setName(svmName);
99-
aggr.setName(aggrName); // TODO: Get aggr list and pick the least used one
100-
101-
volumeRequest.setName(volumeName);
102-
volumeRequest.setSvm(svm);
103-
volumeRequest.setAggregates((List<VolumeRequestDTO.AggregateDTO>) aggr);
104-
volumeRequest.setSize(size);
105-
// Make the POST API call to create the volume
106-
try {
107-
JobResponseDTO response = volumeFeignClient.createVolumeWithJob(authHeader, volumeRequest);
108-
//TODO: Add code to poll the job status until it is completed/ a timeout of 3 mins
109-
110-
} catch (Exception e) {
111-
s_logger.error("Exception while creating volume: ", e);
112-
throw new CloudRuntimeException("Failed to create volume: " + e.getMessage());
113-
}
114-
s_logger.info("Volume created successfully: " + volumeName);
51+
public StorageStrategy getStrategy() {
52+
return storageStrategy;
11553
}
11654
}

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

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,18 @@
1919

2020
package org.apache.cloudstack.storage.service;
2121

22-
public interface NASStrategy {
23-
String createExportPolicy(String svmName, String policyName);
24-
String addExportRule(String policyName, String clientMatch, String[] protocols, String[] roRule, String[] rwRule);
25-
String assignExportPolicyToVolume(String volumeUuid, String policyName);
26-
String enableNFS(String svmUuid);
22+
import org.apache.cloudstack.storage.model.OntapStorage;
23+
24+
import java.util.Map;
25+
26+
public abstract class NASStrategy extends StorageStrategy {
27+
public NASStrategy(OntapStorage ontapStorage) {
28+
super(ontapStorage);
29+
}
30+
31+
public abstract String createExportPolicy(String svmName, String policyName);
32+
public abstract String addExportRule(String policyName, String clientMatch, String[] protocols, String[] roRule, String[] rwRule);
33+
public abstract String assignExportPolicyToVolume(String volumeUuid, String policyName);
34+
public abstract String enableNFS(String svmUuid);
2735
}
2836

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

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,17 @@
1919

2020
package org.apache.cloudstack.storage.service;
2121

22-
public interface SANStrategy {
23-
String createLUN(String svmName, String volumeName, String lunName, long sizeBytes, String osType);
24-
String createIgroup(String svmName, String igroupName, String[] initiators);
25-
String mapLUNToIgroup(String lunName, String igroupName);
26-
String enableISCSI(String svmUuid);
22+
import org.apache.cloudstack.storage.model.OntapStorage;
23+
24+
import java.util.Map;
25+
26+
public abstract class SANStrategy extends StorageStrategy {
27+
public SANStrategy(OntapStorage ontapStorage) {
28+
super(ontapStorage);
29+
}
30+
31+
public abstract String createLUN(String svmName, String volumeName, String lunName, long sizeBytes, String osType);
32+
public abstract String createIgroup(String svmName, String igroupName, String[] initiators);
33+
public abstract String mapLUNToIgroup(String lunName, String igroupName);
34+
public abstract String enableISCSI(String svmUuid);
2735
}

0 commit comments

Comments
 (0)