Skip to content

Commit 43c3684

Browse files
Locharla, SandeepLocharla, Sandeep
authored andcommitted
CSTACKEX-01: Made some changes to fix some errors seen during testing
1 parent fd67a41 commit 43c3684

File tree

3 files changed

+62
-37
lines changed

3 files changed

+62
-37
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@
1919

2020
package org.apache.cloudstack.storage.feign.model.response;
2121

22+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
2223
import com.fasterxml.jackson.annotation.JsonInclude;
2324
import com.fasterxml.jackson.annotation.JsonProperty;
2425
import java.util.List;
2526

2627
/**
2728
* OntapResponse
2829
*/
30+
@JsonIgnoreProperties(ignoreUnknown = true)
2931
@JsonInclude(JsonInclude.Include.NON_NULL)
3032
public class OntapResponse<T> {
3133
@JsonProperty("num_records")

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

Lines changed: 60 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,13 @@ public class OntapPrimaryDatastoreLifecycle extends BasePrimaryDataStoreLifeCycl
6161
@Inject private PrimaryDataStoreHelper _dataStoreHelper;
6262
private static final Logger s_logger = LogManager.getLogger(OntapPrimaryDatastoreLifecycle.class);
6363

64+
// ONTAP minimum volume size is 1.56 GB (1677721600 bytes)
65+
private static final long ONTAP_MIN_VOLUME_SIZE = 1677721600L;
66+
6467
/**
6568
* Creates primary storage on NetApp storage
66-
* @param dsInfos
67-
* @return
69+
* @param dsInfos datastore information map
70+
* @return DataStore instance
6871
*/
6972
@Override
7073
public DataStore initialize(Map<String, Object> dsInfos) {
@@ -80,20 +83,25 @@ public DataStore initialize(Map<String, Object> dsInfos) {
8083
Long capacityBytes = (Long) dsInfos.get("capacityBytes");
8184
String tags = (String) dsInfos.get("tags");
8285
Boolean isTagARule = (Boolean) dsInfos.get("isTagARule");
83-
String scheme = dsInfos.get("scheme").toString();
8486

8587
s_logger.info("Creating ONTAP primary storage pool with name: " + storagePoolName + ", provider: " + providerName +
86-
", zoneId: " + zoneId + ", podId: " + podId + ", clusterId: " + clusterId + ", scheme: " + scheme);
88+
", zoneId: " + zoneId + ", podId: " + podId + ", clusterId: " + clusterId);
89+
s_logger.debug("Received capacityBytes from UI: " + capacityBytes);
8790

8891
// Additional details requested for ONTAP primary storage pool creation
8992
@SuppressWarnings("unchecked")
9093
Map<String, String> details = (Map<String, String>) dsInfos.get("details");
91-
// Validations
92-
if (capacityBytes == null || capacityBytes <= 1677721600L) { // 1.56 GB minimum for ONTAP Volume
93-
throw new IllegalArgumentException("'capacityBytes' must be present and greater than 0.");
94+
95+
// Validate and set capacity
96+
if (capacityBytes == null || capacityBytes <= 0) {
97+
s_logger.warn("capacityBytes not provided or invalid (" + capacityBytes + "), using ONTAP minimum size: " + ONTAP_MIN_VOLUME_SIZE);
98+
capacityBytes = ONTAP_MIN_VOLUME_SIZE;
99+
} else if (capacityBytes < ONTAP_MIN_VOLUME_SIZE) {
100+
s_logger.warn("capacityBytes (" + capacityBytes + ") is below ONTAP minimum (" + ONTAP_MIN_VOLUME_SIZE + "), adjusting to minimum");
101+
capacityBytes = ONTAP_MIN_VOLUME_SIZE;
94102
}
95-
details.put(Constants.SIZE, capacityBytes.toString());
96103

104+
// Validate scope
97105
if (podId == null ^ clusterId == null) {
98106
throw new CloudRuntimeException("Cluster Id or Pod Id is null, cannot create primary storage");
99107
}
@@ -124,7 +132,7 @@ public DataStore initialize(Map<String, Object> dsInfos) {
124132
parameters.setHypervisorType(clusterVO.getHypervisorType());
125133
}
126134

127-
// Get ONTAP details from the URL
135+
// Required ONTAP detail keys
128136
Set<String> requiredKeys = Set.of(
129137
Constants.USERNAME,
130138
Constants.PASSWORD,
@@ -135,80 +143,95 @@ public DataStore initialize(Map<String, Object> dsInfos) {
135143
);
136144

137145
// Parse key=value pairs from URL into details (skip empty segments)
138-
for (String segment : url.split(Constants.SEMICOLON)) {
139-
if (segment.isEmpty()) {
140-
continue;
141-
}
142-
String[] kv = segment.split(Constants.EQUALS, 2);
143-
if (kv.length == 2) {
144-
details.put(kv[0].trim(), kv[1].trim());
146+
if (url != null && !url.isEmpty()) {
147+
for (String segment : url.split(";")) {
148+
if (segment.isEmpty()) {
149+
continue;
150+
}
151+
String[] kv = segment.split("=", 2);
152+
if (kv.length == 2) {
153+
details.put(kv[0].trim(), kv[1].trim());
154+
}
145155
}
146156
}
147157

148-
// Validate existing entries (unexpected keys, empty values)
158+
// Validate existing entries (reject unexpected keys, empty values)
149159
for (Map.Entry<String, String> e : details.entrySet()) {
150160
String key = e.getKey();
151161
String val = e.getValue();
152162
if (!requiredKeys.contains(key)) {
153-
throw new CloudRuntimeException("Unexpected ONTAP key passed in url: " + key);
163+
throw new CloudRuntimeException("Unexpected ONTAP detail key in URL: " + key);
154164
}
155165
if (val == null || val.isEmpty()) {
156166
throw new CloudRuntimeException("ONTAP primary storage creation failed, empty detail: " + key);
157167
}
158168
}
169+
159170
// Detect missing required keys
160-
if (details.size() != requiredKeys.size()) {
171+
Set<String> providedKeys = new java.util.HashSet<>(details.keySet());
172+
if (!providedKeys.containsAll(requiredKeys)) {
161173
Set<String> missing = new java.util.HashSet<>(requiredKeys);
162-
missing.removeAll(details.keySet());
163-
if (!missing.isEmpty()) {
164-
throw new CloudRuntimeException("ONTAP primary storage creation failed, missing detail(s): " + missing);
165-
}
174+
missing.removeAll(providedKeys);
175+
throw new CloudRuntimeException("ONTAP primary storage creation failed, missing detail(s): " + missing);
166176
}
167-
// Default for IS_DISAGGREGATED if needed (after validation of presence)
177+
178+
details.put(Constants.SIZE, capacityBytes.toString());
179+
180+
// Default for IS_DISAGGREGATED if needed
168181
details.putIfAbsent(Constants.IS_DISAGGREGATED, "false");
169182

170-
// TODO: While testing need to check what does this actually do and if the fields corresponding to each protocol should also be set
171-
// TODO: scheme could be 'custom' in our case and we might have to ask 'protocol' separately to the user
172-
String path = "";
183+
// Determine storage pool type and path based on protocol
184+
String path;
173185
ProtocolType protocol = ProtocolType.valueOf(details.get(Constants.PROTOCOL));
174186
switch (protocol) {
175187
case NFS3:
176188
parameters.setType(Storage.StoragePoolType.NetworkFilesystem);
177-
path = "/"+ storagePoolName;
189+
path = details.get(Constants.MANAGEMENT_LIF) + ":/" + storagePoolName;
190+
s_logger.info("Setting NFS path for storage pool: " + path);
178191
break;
179192
case ISCSI:
180193
parameters.setType(Storage.StoragePoolType.Iscsi);
181-
//TODO: path for iSCSI
194+
path = "iqn.1992-08.com.netapp:" + details.get(Constants.SVM_NAME) + "." + storagePoolName;
195+
s_logger.info("Setting iSCSI path for storage pool: " + path);
182196
break;
183197
default:
184198
throw new CloudRuntimeException("Unsupported protocol: " + protocol + ", cannot create primary storage");
185199
}
186200

187-
OntapStorage ontapStorage = new OntapStorage(details.get(Constants.USERNAME), details.get(Constants.PASSWORD),
188-
details.get(Constants.MANAGEMENT_LIF), details.get(Constants.SVM_NAME), protocol,
201+
// Connect to ONTAP and create volume
202+
OntapStorage ontapStorage = new OntapStorage(
203+
details.get(Constants.USERNAME),
204+
details.get(Constants.PASSWORD),
205+
details.get(Constants.MANAGEMENT_LIF),
206+
details.get(Constants.SVM_NAME),
207+
protocol,
189208
Boolean.parseBoolean(details.get(Constants.IS_DISAGGREGATED).toLowerCase()));
209+
190210
StorageStrategy storageStrategy = StorageProviderFactory.getStrategy(ontapStorage);
191211
boolean isValid = storageStrategy.connect();
192212
if (isValid) {
193-
// String volumeName = storagePoolName + "_vol"; //TODO: Figure out a better naming convention
194-
storageStrategy.createStorageVolume(storagePoolName, Long.parseLong((details.get(Constants.SIZE)))); // TODO: size should be in bytes, so see if conversion is needed
213+
long volumeSize = Long.parseLong(details.get(Constants.SIZE));
214+
s_logger.info("Creating ONTAP volume '" + storagePoolName + "' with size: " + volumeSize + " bytes (" +
215+
(volumeSize / (1024 * 1024 * 1024)) + " GB)");
216+
storageStrategy.createStorageVolume(storagePoolName, volumeSize);
195217
} else {
196218
throw new CloudRuntimeException("ONTAP details validation failed, cannot create primary storage");
197219
}
198220

221+
// Set parameters for primary data store
199222
parameters.setHost(details.get(Constants.MANAGEMENT_LIF));
200223
parameters.setPort(Constants.ONTAP_PORT);
201224
parameters.setPath(path);
202-
parameters.setTags(tags);
203-
parameters.setIsTagARule(isTagARule);
225+
parameters.setTags(tags != null ? tags : "");
226+
parameters.setIsTagARule(isTagARule != null ? isTagARule : Boolean.FALSE);
204227
parameters.setDetails(details);
205228
parameters.setUuid(UUID.randomUUID().toString());
206229
parameters.setZoneId(zoneId);
207230
parameters.setPodId(podId);
208231
parameters.setClusterId(clusterId);
209232
parameters.setName(storagePoolName);
210233
parameters.setProviderName(providerName);
211-
parameters.setManaged(true);
234+
parameters.setManaged(true); // ONTAP storage is always managed
212235
parameters.setCapacityBytes(capacityBytes);
213236
parameters.setUsedBytes(0);
214237

@@ -302,3 +325,4 @@ public void changeStoragePoolScopeToCluster(DataStore store, ClusterScope cluste
302325

303326
}
304327
}
328+

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
import com.cloud.utils.exception.CloudRuntimeException;
2323
import feign.FeignException;
24-
import feign.Util;
2524
import org.apache.cloudstack.storage.feign.FeignClientFactory;
2625
import org.apache.cloudstack.storage.feign.client.JobFeignClient;
2726
import org.apache.cloudstack.storage.feign.client.SvmFeignClient;

0 commit comments

Comments
 (0)