Skip to content

Commit b855306

Browse files
Locharla, SandeepLocharla, Sandeep
authored andcommitted
CSTACKEX-01: Create Primary Storage pool changes with working code
1 parent ec1707b commit b855306

18 files changed

+258
-200
lines changed

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

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,15 @@
4444
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
4545
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
4646
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
47+
import org.apache.cloudstack.storage.feign.model.OntapStorage;
48+
import org.apache.cloudstack.storage.provider.StorageProviderFactory;
4749
import org.apache.cloudstack.storage.service.StorageStrategy;
4850
import org.apache.cloudstack.storage.service.model.CloudStackVolume;
4951
import org.apache.cloudstack.storage.service.model.ProtocolType;
5052
import org.apache.cloudstack.storage.utils.Constants;
5153
import org.apache.cloudstack.storage.utils.Utility;
5254
import org.apache.logging.log4j.LogManager;
5355
import org.apache.logging.log4j.Logger;
54-
import com.cloud.utils.component.ComponentContext;
5556

5657
import javax.inject.Inject;
5758
import java.util.HashMap;
@@ -64,9 +65,8 @@ public class OntapPrimaryDatastoreDriver implements PrimaryDataStoreDriver {
6465
private Utility utils;
6566
@Inject private StoragePoolDetailsDao storagePoolDetailsDao;
6667
@Inject private PrimaryDataStoreDao storagePoolDao;
67-
6868
public OntapPrimaryDatastoreDriver() {
69-
utils = ComponentContext.inject(Utility.class);
69+
utils = new Utility();
7070
}
7171
@Override
7272
public Map<String, String> getCapabilities() {
@@ -131,7 +131,7 @@ private String createCloudStackVolumeForTypeVolume(DataStore dataStore, DataObje
131131
throw new CloudRuntimeException("createCloudStackVolume : Storage Pool not found for id: " + dataStore.getId());
132132
}
133133
Map<String, String> details = storagePoolDetailsDao.listDetailsKeyPairs(dataStore.getId());
134-
StorageStrategy storageStrategy = utils.getStrategyByStoragePoolDetails(details);
134+
StorageStrategy storageStrategy = getStrategyByStoragePoolDetails(details);
135135
s_logger.info("createCloudStackVolumeForTypeVolume: Connection to Ontap SVM [{}] successful, preparing CloudStackVolumeRequest", details.get(Constants.SVM_NAME));
136136
CloudStackVolume cloudStackVolumeRequest = utils.createCloudStackVolumeRequestByProtocol(storagePool, details, dataObject);
137137
CloudStackVolume cloudStackVolume = storageStrategy.createCloudStackVolume(cloudStackVolumeRequest);
@@ -273,4 +273,24 @@ public boolean isStorageSupportHA(Storage.StoragePoolType type) {
273273
public void detachVolumeFromAllStorageNodes(Volume volume) {
274274

275275
}
276+
277+
public StorageStrategy getStrategyByStoragePoolDetails(Map<String, String> details) {
278+
if (details == null || details.isEmpty()) {
279+
s_logger.error("getStrategyByStoragePoolDetails: Storage pool details are null or empty");
280+
throw new CloudRuntimeException("getStrategyByStoragePoolDetails: Storage pool details are null or empty");
281+
}
282+
String protocol = details.get(Constants.PROTOCOL);
283+
OntapStorage ontapStorage = new OntapStorage(details.get(Constants.USERNAME), details.get(Constants.PASSWORD),
284+
details.get(Constants.MANAGEMENT_LIF), details.get(Constants.SVM_NAME), ProtocolType.valueOf(protocol),
285+
Boolean.parseBoolean(details.get(Constants.IS_DISAGGREGATED)));
286+
StorageStrategy storageStrategy = StorageProviderFactory.getStrategy(ontapStorage);
287+
boolean isValid = storageStrategy.connect();
288+
if (isValid) {
289+
s_logger.info("Connection to Ontap SVM [{}] successful", details.get(Constants.SVM_NAME));
290+
return storageStrategy;
291+
} else {
292+
s_logger.error("getStrategyByStoragePoolDetails: Connection to Ontap SVM [" + details.get(Constants.SVM_NAME) + "] failed");
293+
throw new CloudRuntimeException("getStrategyByStoragePoolDetails: Connection to Ontap SVM [" + details.get(Constants.SVM_NAME) + "] failed");
294+
}
295+
}
276296
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@ public FeignClientFactory(FeignConfiguration feignConfiguration) {
3333
this.feignConfiguration = feignConfiguration;
3434
}
3535

36-
public <T> T createClient(Class<T> clientClass) {
36+
public <T> T createClient(Class<T> clientClass, String baseURL) {
3737
return Feign.builder()
3838
.client(feignConfiguration.createClient())
3939
.encoder(feignConfiguration.createEncoder())
4040
.decoder(feignConfiguration.createDecoder())
4141
// .logger(feignConfiguration.createLogger())
4242
.retryer(feignConfiguration.createRetryer())
4343
.requestInterceptor(feignConfiguration.createRequestInterceptor())
44-
.target(clientClass, "https://placeholder.com");
44+
.target(clientClass, baseURL);
4545
}
4646
}

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

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import feign.codec.DecodeException;
3131
import feign.codec.EncodeException;
3232
import com.fasterxml.jackson.databind.ObjectMapper;
33+
import com.fasterxml.jackson.databind.DeserializationFeature;
3334
import com.fasterxml.jackson.core.JsonProcessingException;
3435
import org.apache.http.conn.ConnectionKeepAliveStrategy;
3536
import org.apache.http.conn.ssl.NoopHostnameVerifier;
@@ -45,7 +46,6 @@
4546
import java.io.IOException;
4647
import java.lang.reflect.Type;
4748
import java.nio.charset.StandardCharsets;
48-
import java.util.Arrays;
4949
import java.util.concurrent.TimeUnit;
5050

5151
public class FeignConfiguration {
@@ -55,7 +55,13 @@ public class FeignConfiguration {
5555
private final int retryMaxInterval = 5;
5656
private final String ontapFeignMaxConnection = "80";
5757
private final String ontapFeignMaxConnectionPerRoute = "20";
58-
private final ObjectMapper objectMapper = new ObjectMapper();
58+
private final ObjectMapper objectMapper;
59+
60+
public FeignConfiguration() {
61+
this.objectMapper = new ObjectMapper();
62+
// Configure ObjectMapper to ignore unknown properties like _links
63+
this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
64+
}
5965

6066
public Client createClient() {
6167
int maxConn;
@@ -115,9 +121,13 @@ public Encoder createEncoder() {
115121
return new Encoder() {
116122
@Override
117123
public void encode(Object object, Type bodyType, feign.RequestTemplate template) throws EncodeException {
124+
if (object == null) {
125+
template.body((byte[]) null, StandardCharsets.UTF_8);
126+
return;
127+
}
118128
try {
119-
String json = objectMapper.writeValueAsString(object);
120-
template.body(Arrays.toString(json.getBytes(StandardCharsets.UTF_8)));
129+
byte[] jsonBytes = objectMapper.writeValueAsBytes(object);
130+
template.body(jsonBytes, StandardCharsets.UTF_8);
121131
template.header("Content-Type", "application/json");
122132
} catch (JsonProcessingException e) {
123133
throw new EncodeException("Error encoding object to JSON", e);
@@ -133,10 +143,13 @@ public Object decode(Response response, Type type) throws IOException, DecodeExc
133143
if (response.body() == null) {
134144
return null;
135145
}
136-
try {
137-
String json = new String(response.body().asInputStream().readAllBytes(), StandardCharsets.UTF_8);
146+
String json = null;
147+
try (var bodyStream = response.body().asInputStream()) {
148+
json = new String(bodyStream.readAllBytes(), StandardCharsets.UTF_8);
149+
logger.debug("Decoding JSON response: {}", json);
138150
return objectMapper.readValue(json, objectMapper.getTypeFactory().constructType(type));
139151
} catch (IOException e) {
152+
logger.error("Error decoding JSON response. Status: {}, Raw body: {}", response.status(), json, e);
140153
throw new DecodeException(response.status(), "Error decoding JSON response", response.request(), e);
141154
}
142155
}
@@ -147,3 +160,4 @@ public Object decode(Response response, Type type) throws IOException, DecodeExc
147160
// return new Slf4jLogger();
148161
// }
149162
}
163+

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

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,14 @@
2424
import feign.Headers;
2525
import feign.Param;
2626
import feign.RequestLine;
27-
import java.net.URI;
2827

2928
public interface AggregateFeignClient {
3029

31-
@RequestLine("GET /")
32-
@Headers("Authorization: {authHeader}")
33-
OntapResponse<Aggregate> getAggregateResponse(@Param("baseURL") URI baseURL, @Param("authHeader") String authHeader);
30+
@RequestLine("GET /api/storage/aggregates")
31+
@Headers({"Authorization: {authHeader}"})
32+
OntapResponse<Aggregate> getAggregateResponse(@Param("authHeader") String authHeader);
3433

35-
@RequestLine("GET /{uuid}")
36-
@Headers("Authorization: {authHeader}")
37-
Aggregate getAggregateByUUID(@Param("baseURL") URI baseURL, @Param("authHeader") String authHeader, @Param("uuid") String uuid);
34+
@RequestLine("GET /api/storage/aggregates/{uuid}")
35+
@Headers({"Authorization: {authHeader}"})
36+
Aggregate getAggregateByUUID(@Param("authHeader") String authHeader, @Param("uuid") String uuid);
3837
}

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,10 @@
2323
import feign.Headers;
2424
import feign.Param;
2525
import feign.RequestLine;
26-
import java.net.URI;
2726

2827
public interface ClusterFeignClient {
2928

30-
@RequestLine("GET /")
29+
@RequestLine("GET /api/cluster")
3130
@Headers({"Authorization: {authHeader}", "return_records: {returnRecords}"})
32-
Cluster getCluster(@Param("baseURL") URI baseURL, @Param("authHeader") String authHeader, @Param("returnRecords") boolean returnRecords);
31+
Cluster getCluster(@Param("authHeader") String authHeader, @Param("returnRecords") boolean returnRecords);
3332
}

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,10 @@
2222
import feign.Headers;
2323
import feign.Param;
2424
import feign.RequestLine;
25-
import java.net.URI;
2625

2726
public interface JobFeignClient {
2827

29-
@RequestLine("GET /{uuid}")
30-
@Headers("Authorization: {authHeader}")
31-
Job getJobByUUID(@Param("baseURL") URI baseURL, @Param("authHeader") String authHeader, @Param("uuid") String uuid);
28+
@RequestLine("GET /api/cluster/jobs/{uuid}")
29+
@Headers({"Authorization: {authHeader}"})
30+
Job getJobByUUID(@Param("authHeader") String authHeader, @Param("uuid") String uuid);
3231
}

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

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,61 +25,60 @@
2525
import feign.Headers;
2626
import feign.Param;
2727
import feign.RequestLine;
28-
import java.net.URI;
2928

3029
public interface NASFeignClient {
3130

3231
// File Operations
3332
@RequestLine("GET /{volumeUuid}/files/{path}")
34-
@Headers("Authorization: {authHeader}")
35-
OntapResponse<FileInfo> getFileResponse(@Param("uri") URI uri, @Param("authHeader") String authHeader,
33+
@Headers({"Authorization: {authHeader}"})
34+
OntapResponse<FileInfo> getFileResponse(@Param("authHeader") String authHeader,
3635
@Param("volumeUuid") String volumeUUID,
3736
@Param("path") String filePath);
3837

3938
@RequestLine("DELETE /{volumeUuid}/files/{path}")
40-
@Headers("Authorization: {authHeader}")
41-
void deleteFile(@Param("uri") URI uri, @Param("authHeader") String authHeader,
39+
@Headers({"Authorization: {authHeader}"})
40+
void deleteFile(@Param("authHeader") String authHeader,
4241
@Param("volumeUuid") String volumeUUID,
4342
@Param("path") String filePath);
4443

4544
@RequestLine("PATCH /{volumeUuid}/files/{path}")
46-
@Headers("Authorization: {authHeader}")
47-
void updateFile(@Param("uri") URI uri, @Param("authHeader") String authHeader,
45+
@Headers({"Authorization: {authHeader}"})
46+
void updateFile(@Param("authHeader") String authHeader,
4847
@Param("volumeUuid") String volumeUUID,
4948
@Param("path") String filePath,
5049
@Param("fileInfo") FileInfo fileInfo);
5150

5251
@RequestLine("POST /{volumeUuid}/files/{path}")
53-
@Headers("Authorization: {authHeader}")
54-
void createFile(@Param("uri") URI uri, @Param("authHeader") String authHeader,
52+
@Headers({"Authorization: {authHeader}"})
53+
void createFile(@Param("authHeader") String authHeader,
5554
@Param("volumeUuid") String volumeUUID,
5655
@Param("path") String filePath,
5756
@Param("file") FileInfo file);
5857

5958
// Export Policy Operations
6059
@RequestLine("POST /")
6160
@Headers({"Authorization: {authHeader}", "return_records: {returnRecords}"})
62-
ExportPolicy createExportPolicy(@Param("uri") URI uri, @Param("authHeader") String authHeader,
61+
ExportPolicy createExportPolicy(@Param("authHeader") String authHeader,
6362
@Param("returnRecords") boolean returnRecords,
6463
@Param("exportPolicy") ExportPolicy exportPolicy);
6564

6665
@RequestLine("GET /")
67-
@Headers("Authorization: {authHeader}")
68-
OntapResponse<ExportPolicy> getExportPolicyResponse(@Param("baseURL") URI baseURL, @Param("authHeader") String authHeader);
66+
@Headers({"Authorization: {authHeader}"})
67+
OntapResponse<ExportPolicy> getExportPolicyResponse(@Param("authHeader") String authHeader);
6968

7069
@RequestLine("GET /{id}")
71-
@Headers("Authorization: {authHeader}")
72-
OntapResponse<ExportPolicy> getExportPolicyById(@Param("baseURL") URI baseURL, @Param("authHeader") String authHeader,
70+
@Headers({"Authorization: {authHeader}"})
71+
OntapResponse<ExportPolicy> getExportPolicyById(@Param("authHeader") String authHeader,
7372
@Param("id") String id);
7473

7574
@RequestLine("DELETE /{id}")
76-
@Headers("Authorization: {authHeader}")
77-
void deleteExportPolicyById(@Param("baseURL") URI baseURL, @Param("authHeader") String authHeader,
75+
@Headers({"Authorization: {authHeader}"})
76+
void deleteExportPolicyById(@Param("authHeader") String authHeader,
7877
@Param("id") String id);
7978

8079
@RequestLine("PATCH /{id}")
81-
@Headers("Authorization: {authHeader}")
82-
OntapResponse<ExportPolicy> updateExportPolicy(@Param("baseURL") URI baseURL, @Param("authHeader") String authHeader,
80+
@Headers({"Authorization: {authHeader}"})
81+
OntapResponse<ExportPolicy> updateExportPolicy(@Param("authHeader") String authHeader,
8382
@Param("id") String id,
8483
@Param("request") ExportPolicy request);
8584
}

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

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,64 +32,64 @@ public interface SANFeignClient {
3232
// LUN Operation APIs
3333
@RequestLine("POST /")
3434
@Headers({"Authorization: {authHeader}", "return_records: {returnRecords}"})
35-
OntapResponse<Lun> createLun(@Param("baseURL") URI baseURL, @Param("authHeader") String authHeader,
35+
OntapResponse<Lun> createLun(@Param("authHeader") String authHeader,
3636
@Param("returnRecords") boolean returnRecords,
3737
@Param("lun") Lun lun);
3838

3939
@RequestLine("GET /")
40-
@Headers("Authorization: {authHeader}")
41-
OntapResponse<Lun> getLunResponse(@Param("baseURL") URI baseURL, @Param("authHeader") String authHeader);
40+
@Headers({"Authorization: {authHeader}"})
41+
OntapResponse<Lun> getLunResponse(@Param("authHeader") String authHeader);
4242

4343
@RequestLine("GET /{uuid}")
44-
@Headers("Authorization: {authHeader}")
45-
Lun getLunByUUID(@Param("baseURL") URI baseURL, @Param("authHeader") String authHeader, @Param("uuid") String uuid);
44+
@Headers({"Authorization: {authHeader}"})
45+
Lun getLunByUUID(@Param("authHeader") String authHeader, @Param("uuid") String uuid);
4646

4747
@RequestLine("PATCH /{uuid}")
48-
@Headers("Authorization: {authHeader}")
49-
void updateLun(@Param("uri") URI uri, @Param("authHeader") String authHeader, @Param("uuid") String uuid, @Param("lun") Lun lun);
48+
@Headers({"Authorization: {authHeader}"})
49+
void updateLun(@Param("authHeader") String authHeader, @Param("uuid") String uuid, @Param("lun") Lun lun);
5050

5151
@RequestLine("DELETE /{uuid}")
52-
@Headers("Authorization: {authHeader}")
53-
void deleteLun(@Param("baseURL") URI baseURL, @Param("authHeader") String authHeader, @Param("uuid") String uuid);
52+
@Headers({"Authorization: {authHeader}"})
53+
void deleteLun(@Param("authHeader") String authHeader, @Param("uuid") String uuid);
5454

5555
// iGroup Operation APIs
5656
@RequestLine("POST /")
5757
@Headers({"Authorization: {authHeader}", "return_records: {returnRecords}"})
58-
OntapResponse<Igroup> createIgroup(@Param("uri") URI uri, @Param("authHeader") String authHeader,
58+
OntapResponse<Igroup> createIgroup(@Param("authHeader") String authHeader,
5959
@Param("returnRecords") boolean returnRecords,
6060
@Param("igroupRequest") Igroup igroupRequest);
6161

6262
@RequestLine("GET /")
63-
@Headers("Authorization: {authHeader}")
64-
OntapResponse<Igroup> getIgroupResponse(@Param("baseURL") URI baseURL, @Param("authHeader") String authHeader, @Param("uuid") String uuid);
63+
@Headers({"Authorization: {authHeader}"})
64+
OntapResponse<Igroup> getIgroupResponse(@Param("authHeader") String authHeader, @Param("uuid") String uuid);
6565

6666
@RequestLine("GET /{uuid}")
67-
@Headers("Authorization: {authHeader}")
68-
Igroup getIgroupByUUID(@Param("baseURL") URI baseURL, @Param("authHeader") String authHeader, @Param("uuid") String uuid);
67+
@Headers({"Authorization: {authHeader}"})
68+
Igroup getIgroupByUUID(@Param("authHeader") String authHeader, @Param("uuid") String uuid);
6969

7070
@RequestLine("DELETE /{uuid}")
71-
@Headers("Authorization: {authHeader}")
71+
@Headers({"Authorization: {authHeader}"})
7272
void deleteIgroup(@Param("baseUri") URI baseUri, @Param("authHeader") String authHeader, @Param("uuid") String uuid);
7373

7474
@RequestLine("POST /{uuid}/igroups")
7575
@Headers({"Authorization: {authHeader}", "return_records: {returnRecords}"})
76-
OntapResponse<Igroup> addNestedIgroups(@Param("uri") URI uri, @Param("authHeader") String authHeader,
76+
OntapResponse<Igroup> addNestedIgroups(@Param("authHeader") String authHeader,
7777
@Param("uuid") String uuid,
7878
@Param("igroupNestedRequest") Igroup igroupNestedRequest,
7979
@Param("returnRecords") boolean returnRecords);
8080

8181
// LUN Maps Operation APIs
8282
@RequestLine("POST /")
83-
@Headers("Authorization: {authHeader}")
84-
OntapResponse<LunMap> createLunMap(@Param("baseURL") URI baseURL, @Param("authHeader") String authHeader, @Param("lunMap") LunMap lunMap);
83+
@Headers({"Authorization: {authHeader}"})
84+
OntapResponse<LunMap> createLunMap(@Param("authHeader") String authHeader, @Param("lunMap") LunMap lunMap);
8585

8686
@RequestLine("GET /")
87-
@Headers("Authorization: {authHeader}")
88-
OntapResponse<LunMap> getLunMapResponse(@Param("baseURL") URI baseURL, @Param("authHeader") String authHeader);
87+
@Headers({"Authorization: {authHeader}"})
88+
OntapResponse<LunMap> getLunMapResponse(@Param("authHeader") String authHeader);
8989

9090
@RequestLine("DELETE /{lunUuid}/{igroupUuid}")
91-
@Headers("Authorization: {authHeader}")
92-
void deleteLunMap(@Param("baseURL") URI baseURL, @Param("authHeader") String authHeader,
91+
@Headers({"Authorization: {authHeader}"})
92+
void deleteLunMap(@Param("authHeader") String authHeader,
9393
@Param("lunUuid") String lunUuid,
9494
@Param("igroupUuid") String igroupUuid);
9595
}

0 commit comments

Comments
 (0)