Skip to content

Commit ec1707b

Browse files
Locharla, SandeepLocharla, Sandeep
authored andcommitted
CSTACKEX-1: Feign changes and fixes for getting storage pool creation to work
1 parent 6c4b24e commit ec1707b

18 files changed

+414
-330
lines changed

plugins/storage/volume/ontap/pom.xml

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,24 +58,35 @@
5858
<version>${json.version}</version>
5959
</dependency>
6060
<dependency>
61-
<groupId>org.springframework.cloud</groupId>
62-
<artifactId>spring-cloud-commons</artifactId>
61+
<groupId>io.github.openfeign</groupId>
62+
<artifactId>feign-core</artifactId>
63+
<version>${openfeign.version}</version>
6364
</dependency>
6465
<dependency>
65-
<groupId>org.springframework.cloud</groupId>
66-
<artifactId>spring-cloud-starter-openfeign</artifactId>
67-
<exclusions>
68-
<exclusion>
69-
<groupId>org.springframework.security</groupId>
70-
<artifactId>spring-security-crypto</artifactId>
71-
</exclusion>
72-
</exclusions>
66+
<groupId>io.github.openfeign</groupId>
67+
<artifactId>feign-httpclient</artifactId>
68+
<version>${openfeign.version}</version>
7369
</dependency>
70+
<!-- <dependency>-->
71+
<!-- <groupId>io.github.openfeign</groupId>-->
72+
<!-- <artifactId>feign-slf4j</artifactId>-->
73+
<!-- <version>${openfeign.version}</version>-->
74+
<!-- </dependency>-->
7475
<dependency>
7576
<groupId>io.github.openfeign</groupId>
76-
<artifactId>feign-httpclient</artifactId>
77+
<artifactId>feign-jackson</artifactId>
7778
<version>${openfeign.version}</version>
7879
</dependency>
80+
<dependency>
81+
<groupId>com.fasterxml.jackson.core</groupId>
82+
<artifactId>jackson-databind</artifactId>
83+
<version>2.15.2</version>
84+
</dependency>
85+
<dependency>
86+
<groupId>org.apache.httpcomponents</groupId>
87+
<artifactId>httpclient</artifactId>
88+
<version>4.5.14</version>
89+
</dependency>
7990
<dependency>
8091
<groupId>org.apache.cloudstack</groupId>
8192
<artifactId>cloud-engine-storage-volume</artifactId>

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import org.apache.cloudstack.storage.utils.Utility;
5252
import org.apache.logging.log4j.LogManager;
5353
import org.apache.logging.log4j.Logger;
54+
import com.cloud.utils.component.ComponentContext;
5455

5556
import javax.inject.Inject;
5657
import java.util.HashMap;
@@ -60,9 +61,13 @@ public class OntapPrimaryDatastoreDriver implements PrimaryDataStoreDriver {
6061

6162
private static final Logger s_logger = LogManager.getLogger(OntapPrimaryDatastoreDriver.class);
6263

63-
@Inject private Utility utils;
64+
private Utility utils;
6465
@Inject private StoragePoolDetailsDao storagePoolDetailsDao;
6566
@Inject private PrimaryDataStoreDao storagePoolDao;
67+
68+
public OntapPrimaryDatastoreDriver() {
69+
utils = ComponentContext.inject(Utility.class);
70+
}
6671
@Override
6772
public Map<String, String> getCapabilities() {
6873
s_logger.trace("OntapPrimaryDatastoreDriver: getCapabilities: Called");
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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.feign;
21+
22+
import feign.Feign;
23+
24+
public class FeignClientFactory {
25+
26+
private final FeignConfiguration feignConfiguration;
27+
28+
public FeignClientFactory() {
29+
this.feignConfiguration = new FeignConfiguration();
30+
}
31+
32+
public FeignClientFactory(FeignConfiguration feignConfiguration) {
33+
this.feignConfiguration = feignConfiguration;
34+
}
35+
36+
public <T> T createClient(Class<T> clientClass) {
37+
return Feign.builder()
38+
.client(feignConfiguration.createClient())
39+
.encoder(feignConfiguration.createEncoder())
40+
.decoder(feignConfiguration.createDecoder())
41+
// .logger(feignConfiguration.createLogger())
42+
.retryer(feignConfiguration.createRetryer())
43+
.requestInterceptor(feignConfiguration.createRequestInterceptor())
44+
.target(clientClass, "https://placeholder.com");
45+
}
46+
}

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

Lines changed: 68 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,41 +19,45 @@
1919

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

22-
2322
import feign.RequestInterceptor;
24-
import feign.RequestTemplate;
2523
import feign.Retryer;
26-
import org.springframework.cloud.commons.httpclient.ApacheHttpClientFactory;
24+
import feign.Client;
25+
import feign.httpclient.ApacheHttpClient;
26+
import feign.codec.Decoder;
27+
import feign.codec.Encoder;
28+
//import feign.slf4j.Slf4jLogger;
29+
import feign.Response;
30+
import feign.codec.DecodeException;
31+
import feign.codec.EncodeException;
32+
import com.fasterxml.jackson.databind.ObjectMapper;
33+
import com.fasterxml.jackson.core.JsonProcessingException;
2734
import org.apache.http.conn.ConnectionKeepAliveStrategy;
2835
import org.apache.http.conn.ssl.NoopHostnameVerifier;
2936
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
3037
import org.apache.http.conn.ssl.TrustAllStrategy;
3138
import org.apache.http.impl.client.CloseableHttpClient;
39+
import org.apache.http.impl.client.HttpClientBuilder;
3240
import org.apache.http.ssl.SSLContexts;
3341
import org.apache.logging.log4j.LogManager;
3442
import org.apache.logging.log4j.Logger;
35-
import org.springframework.context.annotation.Bean;
36-
import org.springframework.context.annotation.Configuration;
37-
import feign.Client;
38-
import feign.httpclient.ApacheHttpClient;
43+
3944
import javax.net.ssl.SSLContext;
45+
import java.io.IOException;
46+
import java.lang.reflect.Type;
47+
import java.nio.charset.StandardCharsets;
48+
import java.util.Arrays;
4049
import java.util.concurrent.TimeUnit;
4150

42-
@Configuration
4351
public class FeignConfiguration {
44-
private static Logger logger = LogManager.getLogger(FeignConfiguration.class);
52+
private static final Logger logger = LogManager.getLogger(FeignConfiguration.class);
4553

46-
private int retryMaxAttempt = 3;
47-
48-
private int retryMaxInterval = 5;
49-
50-
private String ontapFeignMaxConnection = "80";
51-
52-
private String ontapFeignMaxConnectionPerRoute = "20";
53-
54-
@Bean
55-
public Client client(ApacheHttpClientFactory httpClientFactory) {
54+
private final int retryMaxAttempt = 3;
55+
private final int retryMaxInterval = 5;
56+
private final String ontapFeignMaxConnection = "80";
57+
private final String ontapFeignMaxConnectionPerRoute = "20";
58+
private final ObjectMapper objectMapper = new ObjectMapper();
5659

60+
public Client createClient() {
5761
int maxConn;
5862
int maxConnPerRoute;
5963
try {
@@ -68,10 +72,11 @@ public Client client(ApacheHttpClientFactory httpClientFactory) {
6872
logger.error("ontapFeignClient: encounter exception while parse the max connection per route from env. setting default value");
6973
maxConnPerRoute = 2;
7074
}
75+
7176
// Disable Keep Alive for Http Connection
7277
logger.debug("ontapFeignClient: Setting the feign client config values as max connection: {}, max connections per route: {}", maxConn, maxConnPerRoute);
7378
ConnectionKeepAliveStrategy keepAliveStrategy = (response, context) -> 0;
74-
CloseableHttpClient httpClient = httpClientFactory.createBuilder()
79+
CloseableHttpClient httpClient = HttpClientBuilder.create()
7580
.setMaxConnTotal(maxConn)
7681
.setMaxConnPerRoute(maxConnPerRoute)
7782
.setKeepAliveStrategy(keepAliveStrategy)
@@ -91,22 +96,54 @@ private SSLConnectionSocketFactory getSSLSocketFactory() {
9196
}
9297
}
9398

99+
public RequestInterceptor createRequestInterceptor() {
100+
return template -> {
101+
logger.info("Feign Request URL: {}", template.url());
102+
logger.info("HTTP Method: {}", template.method());
103+
logger.info("Headers: {}", template.headers());
104+
if (template.body() != null) {
105+
logger.info("Body: {}", new String(template.body()));
106+
}
107+
};
108+
}
109+
110+
public Retryer createRetryer() {
111+
return new Retryer.Default(1000L, retryMaxInterval * 1000L, retryMaxAttempt);
112+
}
94113

95-
@Bean
96-
public RequestInterceptor requestInterceptor() {
97-
return new RequestInterceptor() {
114+
public Encoder createEncoder() {
115+
return new Encoder() {
98116
@Override
99-
public void apply(RequestTemplate template) {
100-
logger.info("Feign Request URL: {}", template.url());
101-
logger.info("HTTP Method: {}", template.method());
102-
logger.info("Headers: {}", template.headers());
103-
logger.info("Body: {}", template.requestBody().asString());
117+
public void encode(Object object, Type bodyType, feign.RequestTemplate template) throws EncodeException {
118+
try {
119+
String json = objectMapper.writeValueAsString(object);
120+
template.body(Arrays.toString(json.getBytes(StandardCharsets.UTF_8)));
121+
template.header("Content-Type", "application/json");
122+
} catch (JsonProcessingException e) {
123+
throw new EncodeException("Error encoding object to JSON", e);
124+
}
104125
}
105126
};
106127
}
107128

108-
@Bean
109-
public Retryer feignRetryer() {
110-
return new Retryer.Default(1000L, retryMaxInterval * 1000L, retryMaxAttempt);
129+
public Decoder createDecoder() {
130+
return new Decoder() {
131+
@Override
132+
public Object decode(Response response, Type type) throws IOException, DecodeException {
133+
if (response.body() == null) {
134+
return null;
135+
}
136+
try {
137+
String json = new String(response.body().asInputStream().readAllBytes(), StandardCharsets.UTF_8);
138+
return objectMapper.readValue(json, objectMapper.getTypeFactory().constructType(type));
139+
} catch (IOException e) {
140+
throw new DecodeException(response.status(), "Error decoding JSON response", response.request(), e);
141+
}
142+
}
143+
};
111144
}
145+
146+
// public Slf4jLogger createLogger() {
147+
// return new Slf4jLogger();
148+
// }
112149
}

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

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,26 +20,19 @@
2020
package org.apache.cloudstack.storage.feign.client;
2121

2222
import org.apache.cloudstack.storage.feign.model.Aggregate;
23-
import org.apache.cloudstack.storage.feign.FeignConfiguration;
2423
import org.apache.cloudstack.storage.feign.model.response.OntapResponse;
25-
import org.springframework.cloud.openfeign.FeignClient;
26-
import org.springframework.context.annotation.Lazy;
27-
import org.springframework.web.bind.annotation.PathVariable;
28-
import org.springframework.web.bind.annotation.RequestHeader;
29-
import org.springframework.web.bind.annotation.RequestMapping;
30-
import org.springframework.web.bind.annotation.RequestMethod;
31-
24+
import feign.Headers;
25+
import feign.Param;
26+
import feign.RequestLine;
3227
import java.net.URI;
3328

34-
@Lazy
35-
@FeignClient(name="AggregateClient", url="https://{clusterIP}/api/storage/aggregates", configuration = FeignConfiguration.class)
3629
public interface AggregateFeignClient {
3730

38-
//this method to get all aggregates and also filtered aggregates based on query params as a part of URL
39-
@RequestMapping(method=RequestMethod.GET)
40-
OntapResponse<Aggregate> getAggregateResponse(URI baseURL, @RequestHeader("Authorization") String header);
41-
42-
@RequestMapping(method=RequestMethod.GET, value="/{uuid}")
43-
Aggregate getAggregateByUUID(URI baseURL,@RequestHeader("Authorization") String header, @PathVariable(name = "uuid", required = true) String uuid);
31+
@RequestLine("GET /")
32+
@Headers("Authorization: {authHeader}")
33+
OntapResponse<Aggregate> getAggregateResponse(@Param("baseURL") URI baseURL, @Param("authHeader") String authHeader);
4434

35+
@RequestLine("GET /{uuid}")
36+
@Headers("Authorization: {authHeader}")
37+
Aggregate getAggregateByUUID(@Param("baseURL") URI baseURL, @Param("authHeader") String authHeader, @Param("uuid") String uuid);
4538
}

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

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,15 @@
1919

2020
package org.apache.cloudstack.storage.feign.client;
2121

22-
import org.apache.cloudstack.storage.feign.FeignConfiguration;
2322
import org.apache.cloudstack.storage.feign.model.Cluster;
24-
import org.springframework.cloud.openfeign.FeignClient;
25-
import org.springframework.web.bind.annotation.RequestHeader;
26-
import org.springframework.web.bind.annotation.RequestMapping;
27-
import org.springframework.web.bind.annotation.RequestMethod;
28-
23+
import feign.Headers;
24+
import feign.Param;
25+
import feign.RequestLine;
2926
import java.net.URI;
3027

31-
@FeignClient(name="ClusterClient", url="https://{clusterIP}/api/cluster", configuration = FeignConfiguration.class)
3228
public interface ClusterFeignClient {
3329

34-
@RequestMapping(method= RequestMethod.GET)
35-
Cluster getCluster(URI baseURL, @RequestHeader("Authorization") String header, @RequestHeader("return_records") boolean value);
36-
30+
@RequestLine("GET /")
31+
@Headers({"Authorization: {authHeader}", "return_records: {returnRecords}"})
32+
Cluster getCluster(@Param("baseURL") URI baseURL, @Param("authHeader") String authHeader, @Param("returnRecords") boolean returnRecords);
3733
}

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

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,15 @@
1818
*/
1919
package org.apache.cloudstack.storage.feign.client;
2020

21-
import org.apache.cloudstack.storage.feign.FeignConfiguration;
2221
import org.apache.cloudstack.storage.feign.model.Job;
23-
import org.springframework.cloud.openfeign.FeignClient;
24-
import org.springframework.context.annotation.Lazy;
25-
import org.springframework.web.bind.annotation.PathVariable;
26-
import org.springframework.web.bind.annotation.RequestHeader;
27-
import org.springframework.web.bind.annotation.RequestMapping;
28-
import org.springframework.web.bind.annotation.RequestMethod;
22+
import feign.Headers;
23+
import feign.Param;
24+
import feign.RequestLine;
2925
import java.net.URI;
3026

31-
/**
32-
* @author Administrator
33-
*
34-
*/
35-
@Lazy
36-
@FeignClient(name = "JobClient", url = "https://{clusterIP}/api/cluster/jobs" , configuration = FeignConfiguration.class)
3727
public interface JobFeignClient {
3828

39-
@RequestMapping(method = RequestMethod.GET, value="/{uuid}")
40-
Job getJobByUUID(URI baseURL, @RequestHeader("Authorization") String header, @PathVariable(name = "uuid", required = true) String uuid);
41-
29+
@RequestLine("GET /{uuid}")
30+
@Headers("Authorization: {authHeader}")
31+
Job getJobByUUID(@Param("baseURL") URI baseURL, @Param("authHeader") String authHeader, @Param("uuid") String uuid);
4232
}

0 commit comments

Comments
 (0)