Skip to content

Commit eb3bf40

Browse files
filiphrwilkinsona
authored andcommitted
Bring back Elasticsearch RestClient auto-configuration
Prior to this commit, Spring Boot would only auto-configure the `RestHighLevelClient` and `RestClientBuilder` if the `RestHighLevelClient` was present. This was done in 1d73d4e. This commit brings back the exposing of the `RestClient` bean in when exposing the `RestHighLevelClient` or when the `RestHighLevelClient` is not present. It allows for using the auto-configuration and its customizers of the `RestClientBuilder` in a similar way as it is done for the `RestTemplateBuilder` and the `WebClient.Builder`. The presence of the `elasticsearch-rest-high-level-client` module is now optional. This opens the door for potentially adding support for the new Elasticsearch Java Client[1] that is based on the same `RestClient`. The health contributor and its configuration has also been updated to only depend on the low-level RestClient. See gh-28496 [1] https://github.com/elastic/elasticsearch-java
1 parent e0ae1d3 commit eb3bf40

File tree

13 files changed

+604
-104
lines changed

13 files changed

+604
-104
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchRestHealthContributorAutoConfiguration.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,13 @@
4444
@ConditionalOnClass(org.elasticsearch.client.RestHighLevelClient.class)
4545
@ConditionalOnBean(org.elasticsearch.client.RestHighLevelClient.class)
4646
@ConditionalOnEnabledHealthIndicator("elasticsearch")
47-
public class ElasticSearchRestHealthContributorAutoConfiguration extends
48-
CompositeHealthContributorConfiguration<ElasticsearchRestHealthIndicator, org.elasticsearch.client.RestHighLevelClient> {
47+
public class ElasticSearchRestHealthContributorAutoConfiguration
48+
extends CompositeHealthContributorConfiguration<ElasticsearchRestHealthIndicator, RestClient> {
4949

5050
@Bean
5151
@ConditionalOnMissingBean(name = { "elasticsearchHealthIndicator", "elasticsearchHealthContributor" })
52-
public HealthContributor elasticsearchHealthContributor(
53-
Map<String, org.elasticsearch.client.RestHighLevelClient> clients) {
52+
public HealthContributor elasticsearchHealthContributor(Map<String, RestClient> clients) {
5453
return createContributor(clients);
5554
}
5655

57-
}
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright 2012-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.elasticsearch;
18+
19+
import java.util.Map;
20+
21+
import org.elasticsearch.client.RestClient;
22+
23+
import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration;
24+
import org.springframework.boot.actuate.elasticsearch.ElasticsearchRestClientHealthIndicator;
25+
import org.springframework.boot.actuate.health.HealthContributor;
26+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
27+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
28+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
29+
import org.springframework.context.annotation.Bean;
30+
import org.springframework.context.annotation.Configuration;
31+
32+
/**
33+
* Elasticsearch rest client health contributor configurations.
34+
*
35+
* @author Filip Hrisafov
36+
*/
37+
class ElasticSearchRestHealthContributorConfigurations {
38+
39+
@Configuration(proxyBeanMethods = false)
40+
@ConditionalOnClass(org.elasticsearch.client.RestHighLevelClient.class)
41+
@ConditionalOnBean(org.elasticsearch.client.RestHighLevelClient.class)
42+
@Deprecated
43+
static class RestHighLevelClientHealthContributorConfiguration extends
44+
CompositeHealthContributorConfiguration<org.springframework.boot.actuate.elasticsearch.ElasticsearchRestHealthIndicator, org.elasticsearch.client.RestHighLevelClient> {
45+
46+
@Bean
47+
@ConditionalOnMissingBean(name = { "elasticsearchHealthIndicator", "elasticsearchHealthContributor" })
48+
HealthContributor elasticsearchHealthContributor(
49+
Map<String, org.elasticsearch.client.RestHighLevelClient> clients) {
50+
return createContributor(clients);
51+
}
52+
53+
}
54+
55+
@Configuration(proxyBeanMethods = false)
56+
@ConditionalOnBean(RestClient.class)
57+
@ConditionalOnMissingBean(org.elasticsearch.client.RestHighLevelClient.class)
58+
static class RestClientHealthContributorConfiguration
59+
extends CompositeHealthContributorConfiguration<ElasticsearchRestClientHealthIndicator, RestClient> {
60+
61+
@Bean
62+
@ConditionalOnMissingBean(name = { "elasticsearchHealthIndicator", "elasticsearchHealthContributor" })
63+
HealthContributor elasticsearchHealthContributor(Map<String, RestClient> clients) {
64+
return createContributor(clients);
65+
}
66+
67+
}
68+
69+
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticsearchReactiveHealthContributorAutoConfigurationTests.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ void runShouldCreateIndicator() {
5050
}
5151

5252
@Test
53+
@SuppressWarnings("deprecation")
5354
void runWithRegularIndicatorShouldOnlyCreateReactiveIndicator() {
5455
this.contextRunner
5556
.withConfiguration(AutoConfigurations.of(ElasticSearchRestHealthContributorAutoConfiguration.class))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.elasticsearch;
18+
19+
import org.elasticsearch.client.RestClient;
20+
import org.elasticsearch.client.RestClientBuilder;
21+
import org.junit.jupiter.api.Test;
22+
23+
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
24+
import org.springframework.boot.actuate.elasticsearch.ElasticsearchRestClientHealthIndicator;
25+
import org.springframework.boot.actuate.elasticsearch.ElasticsearchRestHealthIndicator;
26+
import org.springframework.boot.autoconfigure.AutoConfigurations;
27+
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration;
28+
import org.springframework.boot.test.context.FilteredClassLoader;
29+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
30+
import org.springframework.context.annotation.Bean;
31+
import org.springframework.context.annotation.Configuration;
32+
33+
import static org.assertj.core.api.Assertions.assertThat;
34+
35+
/**
36+
* Tests for {@link ElasticsearchRestClientAutoConfiguration}.
37+
*
38+
* @author Filip Hrisafov
39+
*/
40+
class ElasticsearchRestHealthContributorAutoConfigurationTests {
41+
42+
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
43+
.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class,
44+
ElasticSearchRestHealthContributorAutoConfiguration.class,
45+
HealthContributorAutoConfiguration.class));
46+
47+
@Test
48+
@SuppressWarnings("deprecation")
49+
void runShouldCreateIndicator() {
50+
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestHealthIndicator.class)
51+
.hasBean("elasticsearchHealthContributor"));
52+
}
53+
54+
@Test
55+
void runWithoutRestHighLevelClientAndWithoutRestClientShouldNotCreateIndicator() {
56+
this.contextRunner
57+
.withClassLoader(
58+
new FilteredClassLoader(org.elasticsearch.client.RestHighLevelClient.class, RestClient.class))
59+
.run((context) -> assertThat(context).doesNotHaveBean(ElasticsearchRestClientHealthIndicator.class)
60+
.doesNotHaveBean("elasticsearchHealthContributor"));
61+
}
62+
63+
@Test
64+
@SuppressWarnings("deprecation")
65+
void runWithoutRestHighLevelClientAndWithRestClientShouldCreateIndicator() {
66+
this.contextRunner.withUserConfiguration(CustomRestClientConfiguration.class)
67+
.run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestClientHealthIndicator.class)
68+
.doesNotHaveBean(ElasticsearchRestHealthIndicator.class)
69+
.hasBean("elasticsearchHealthContributor"));
70+
}
71+
72+
@Test
73+
@SuppressWarnings("deprecation")
74+
void runWithRestHighLevelClientAndWithRestClientShouldCreateIndicator() {
75+
this.contextRunner.withUserConfiguration(CustomRestHighClientConfiguration.class)
76+
.run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestClientHealthIndicator.class)
77+
.hasBean("elasticsearchHealthContributor"));
78+
}
79+
80+
@Test
81+
void runWhenDisabledShouldNotCreateIndicator() {
82+
this.contextRunner.withPropertyValues("management.health.elasticsearch.enabled:false")
83+
.run((context) -> assertThat(context).doesNotHaveBean(ElasticsearchRestClientHealthIndicator.class)
84+
.doesNotHaveBean("elasticsearchHealthContributor"));
85+
}
86+
87+
@Configuration(proxyBeanMethods = false)
88+
static class CustomRestClientConfiguration {
89+
90+
@Bean
91+
RestClient customRestClient(RestClientBuilder builder) {
92+
return builder.build();
93+
}
94+
95+
}
96+
97+
@Configuration(proxyBeanMethods = false)
98+
@SuppressWarnings("deprecation")
99+
static class CustomRestHighClientConfiguration {
100+
101+
@Bean
102+
org.elasticsearch.client.RestHighLevelClient customRestHighClient(RestClientBuilder builder) {
103+
return new org.elasticsearch.client.RestHighLevelClient(builder);
104+
}
105+
106+
@Bean
107+
RestClient customClient(org.elasticsearch.client.RestHighLevelClient restHighLevelClient) {
108+
return restHighLevelClient.getLowLevelClient();
109+
}
110+
111+
}
112+
113+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.elasticsearch;
18+
19+
import java.io.InputStream;
20+
import java.nio.charset.StandardCharsets;
21+
import java.util.Map;
22+
23+
import org.apache.http.HttpStatus;
24+
import org.apache.http.StatusLine;
25+
import org.elasticsearch.client.Request;
26+
import org.elasticsearch.client.Response;
27+
import org.elasticsearch.client.RestClient;
28+
29+
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
30+
import org.springframework.boot.actuate.health.Health;
31+
import org.springframework.boot.actuate.health.HealthIndicator;
32+
import org.springframework.boot.json.JsonParser;
33+
import org.springframework.boot.json.JsonParserFactory;
34+
import org.springframework.util.StreamUtils;
35+
36+
/**
37+
* {@link HealthIndicator} for an Elasticsearch cluster using a {@link RestClient}.
38+
*
39+
* @author Artsiom Yudovin
40+
* @author Brian Clozel
41+
* @author Filip Hrisafov
42+
* @since 2.7
43+
*/
44+
public class ElasticsearchRestClientHealthIndicator extends AbstractHealthIndicator {
45+
46+
private static final String RED_STATUS = "red";
47+
48+
private final RestClient client;
49+
50+
private final JsonParser jsonParser;
51+
52+
public ElasticsearchRestClientHealthIndicator(RestClient client) {
53+
super("Elasticsearch health check failed");
54+
this.client = client;
55+
this.jsonParser = JsonParserFactory.getJsonParser();
56+
}
57+
58+
@Override
59+
protected void doHealthCheck(Health.Builder builder) throws Exception {
60+
Response response = this.client.performRequest(new Request("GET", "/_cluster/health/"));
61+
StatusLine statusLine = response.getStatusLine();
62+
if (statusLine.getStatusCode() != HttpStatus.SC_OK) {
63+
builder.down();
64+
builder.withDetail("statusCode", statusLine.getStatusCode());
65+
builder.withDetail("reasonPhrase", statusLine.getReasonPhrase());
66+
return;
67+
}
68+
try (InputStream inputStream = response.getEntity().getContent()) {
69+
doHealthCheck(builder, StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8));
70+
}
71+
}
72+
73+
private void doHealthCheck(Health.Builder builder, String json) {
74+
Map<String, Object> response = this.jsonParser.parseMap(json);
75+
String status = (String) response.get("status");
76+
if (RED_STATUS.equals(status)) {
77+
builder.outOfService();
78+
}
79+
else {
80+
builder.up();
81+
}
82+
builder.withDetails(response);
83+
}
84+
85+
}

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchRestHealthIndicator.java

Lines changed: 5 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,9 @@
1616

1717
package org.springframework.boot.actuate.elasticsearch;
1818

19-
import java.io.InputStream;
20-
import java.nio.charset.StandardCharsets;
21-
import java.util.Map;
22-
23-
import org.apache.http.HttpStatus;
24-
import org.apache.http.StatusLine;
25-
import org.elasticsearch.client.Request;
26-
import org.elasticsearch.client.Response;
2719
import org.elasticsearch.client.RestClient;
2820

29-
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
30-
import org.springframework.boot.actuate.health.Health;
3121
import org.springframework.boot.actuate.health.HealthIndicator;
32-
import org.springframework.boot.json.JsonParser;
33-
import org.springframework.boot.json.JsonParserFactory;
34-
import org.springframework.util.StreamUtils;
3522

3623
/**
3724
* {@link HealthIndicator} for an Elasticsearch cluster using a {@link RestClient}.
@@ -40,51 +27,19 @@
4027
* @author Brian Clozel
4128
* @author Filip Hrisafov
4229
* @since 2.1.1
30+
* @deprecated since 2.7.0 for removal in 2.9.0 in favor of
31+
* {@link ElasticsearchRestClientHealthIndicator}
4332
*/
44-
public class ElasticsearchRestHealthIndicator extends AbstractHealthIndicator {
45-
46-
private static final String RED_STATUS = "red";
47-
48-
private final RestClient client;
49-
50-
private final JsonParser jsonParser;
33+
@Deprecated
34+
public class ElasticsearchRestHealthIndicator extends ElasticsearchRestClientHealthIndicator {
5135

5236
@SuppressWarnings("deprecation")
5337
public ElasticsearchRestHealthIndicator(org.elasticsearch.client.RestHighLevelClient client) {
5438
this(client.getLowLevelClient());
5539
}
5640

5741
public ElasticsearchRestHealthIndicator(RestClient client) {
58-
super("Elasticsearch health check failed");
59-
this.client = client;
60-
this.jsonParser = JsonParserFactory.getJsonParser();
61-
}
62-
63-
@Override
64-
protected void doHealthCheck(Health.Builder builder) throws Exception {
65-
Response response = this.client.performRequest(new Request("GET", "/_cluster/health/"));
66-
StatusLine statusLine = response.getStatusLine();
67-
if (statusLine.getStatusCode() != HttpStatus.SC_OK) {
68-
builder.down();
69-
builder.withDetail("statusCode", statusLine.getStatusCode());
70-
builder.withDetail("reasonPhrase", statusLine.getReasonPhrase());
71-
return;
72-
}
73-
try (InputStream inputStream = response.getEntity().getContent()) {
74-
doHealthCheck(builder, StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8));
75-
}
76-
}
77-
78-
private void doHealthCheck(Health.Builder builder, String json) {
79-
Map<String, Object> response = this.jsonParser.parseMap(json);
80-
String status = (String) response.get("status");
81-
if (RED_STATUS.equals(status)) {
82-
builder.outOfService();
83-
}
84-
else {
85-
builder.up();
86-
}
87-
builder.withDetails(response);
42+
super(client);
8843
}
8944

9045
}

0 commit comments

Comments
 (0)