From 21af08bd2a3a836d1a144ecf3cd6eaecac41eae2 Mon Sep 17 00:00:00 2001 From: Aleksander Lech Date: Mon, 20 Apr 2020 18:30:04 +0400 Subject: [PATCH] Added support for healthcheck for ReactiveElasticsearchClient --- .../build.gradle | 1 + ...iveHealthContributorAutoConfiguration.java | 59 ++++++++++++++++ ...estHealthContributorAutoConfiguration.java | 4 +- .../main/resources/META-INF/spring.factories | 1 + ...althContributorAutoConfigurationTests.java | 67 +++++++++++++++++++ .../spring-boot-actuator/build.gradle | 1 + .../ElasticsearchReactiveHealthIndicator.java | 61 +++++++++++++++++ 7 files changed, 192 insertions(+), 2 deletions(-) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchReactiveHealthContributorAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticsearchReactiveHealthContributorAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchReactiveHealthIndicator.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle b/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle index c8166427eef9..286db3e2698f 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle @@ -99,6 +99,7 @@ dependencies { optional("org.springframework.data:spring-data-mongodb") optional("org.springframework.data:spring-data-neo4j") optional("org.springframework.data:spring-data-redis") + optional("org.springframework.data:spring-data-elasticsearch") optional("org.springframework.data:spring-data-solr") optional("org.springframework.integration:spring-integration-core") optional("org.springframework.kafka:spring-kafka") diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchReactiveHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchReactiveHealthContributorAutoConfiguration.java new file mode 100644 index 000000000000..5d998fb9e7fb --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchReactiveHealthContributorAutoConfiguration.java @@ -0,0 +1,59 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.autoconfigure.elasticsearch; + +import java.util.Map; + +import reactor.core.publisher.Flux; + +import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthContributorConfiguration; +import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; +import org.springframework.boot.actuate.elasticsearch.ElasticsearchReactiveHealthIndicator; +import org.springframework.boot.actuate.health.ReactiveHealthContributor; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRestClientAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for + * {@link ElasticsearchReactiveHealthIndicator} using the + * {@link ReactiveElasticsearchClient}. + * + * @author Aleksander Lech + * @since 2.3 + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass({ ReactiveElasticsearchClient.class, Flux.class }) +@ConditionalOnBean(ReactiveElasticsearchClient.class) +@ConditionalOnEnabledHealthIndicator("elasticsearch") +@AutoConfigureAfter(ReactiveElasticsearchRestClientAutoConfiguration.class) +public class ElasticSearchReactiveHealthContributorAutoConfiguration extends + CompositeReactiveHealthContributorConfiguration { + + @Bean + @ConditionalOnMissingBean(name = { "elasticsearchHealthIndicator", "elasticsearchHealthContributor" }) + public ReactiveHealthContributor elasticsearchHealthContributor(Map clients) { + return createContributor(clients); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchRestHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchRestHealthContributorAutoConfiguration.java index 5e7787053a73..c69b9b0e43c9 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchRestHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchRestHealthContributorAutoConfiguration.java @@ -49,8 +49,8 @@ public class ElasticSearchRestHealthContributorAutoConfiguration extends CompositeHealthContributorConfiguration { @Bean - @ConditionalOnMissingBean(name = { "elasticsearchRestHealthIndicator", "elasticsearchRestHealthContributor" }) - public HealthContributor elasticsearchRestHealthContributor(Map clients) { + @ConditionalOnMissingBean(name = { "elasticsearchHealthIndicator", "elasticsearchHealthContributor" }) + public HealthContributor elasticsearchHealthContributor(Map clients) { return createContributor(clients); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index 0771aebd53c3..5c7f1843aa73 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -15,6 +15,7 @@ org.springframework.boot.actuate.autoconfigure.context.ShutdownEndpointAutoConfi org.springframework.boot.actuate.autoconfigure.couchbase.CouchbaseHealthContributorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.couchbase.CouchbaseReactiveHealthContributorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.elasticsearch.ElasticSearchRestHealthContributorAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.elasticsearch.ElasticSearchReactiveHealthContributorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.endpoint.jmx.JmxEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticsearchReactiveHealthContributorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticsearchReactiveHealthContributorAutoConfigurationTests.java new file mode 100644 index 000000000000..391bcda780d2 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticsearchReactiveHealthContributorAutoConfigurationTests.java @@ -0,0 +1,67 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.autoconfigure.elasticsearch; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration; +import org.springframework.boot.actuate.elasticsearch.ElasticsearchReactiveHealthIndicator; +import org.springframework.boot.actuate.elasticsearch.ElasticsearchRestHealthIndicator; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration; +import org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRestClientAutoConfiguration; +import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ElasticSearchReactiveHealthContributorAutoConfiguration}. + * + * @author Aleksander Lech + */ +class ElasticsearchReactiveHealthContributorAutoConfigurationTests { + + private ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(AutoConfigurations + .of(ElasticsearchDataAutoConfiguration.class, ReactiveElasticsearchRestClientAutoConfiguration.class, + ElasticsearchRestClientAutoConfiguration.class, + ElasticSearchReactiveHealthContributorAutoConfiguration.class, + HealthContributorAutoConfiguration.class)); + + @Test + void runShouldCreateIndicator() { + this.contextRunner.run((context) -> assertThat(context) + .hasSingleBean(ElasticsearchReactiveHealthIndicator.class).hasBean("elasticsearchHealthContributor")); + } + + @Test + void runWithRegularIndicatorShouldOnlyCreateReactiveIndicator() { + this.contextRunner + .withConfiguration(AutoConfigurations.of(ElasticSearchRestHealthContributorAutoConfiguration.class)) + .run((context) -> assertThat(context).hasSingleBean(ElasticsearchReactiveHealthIndicator.class) + .hasBean("elasticsearchHealthContributor") + .doesNotHaveBean(ElasticsearchRestHealthIndicator.class)); + } + + @Test + void runWhenDisabledShouldNotCreateIndicator() { + this.contextRunner.withPropertyValues("management.health.elasticsearch.enabled:false") + .run((context) -> assertThat(context).doesNotHaveBean(ElasticsearchReactiveHealthIndicator.class) + .doesNotHaveBean("elasticsearchHealthContributor")); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/build.gradle b/spring-boot-project/spring-boot-actuator/build.gradle index ae3cdc34e9a3..9b346355a027 100644 --- a/spring-boot-project/spring-boot-actuator/build.gradle +++ b/spring-boot-project/spring-boot-actuator/build.gradle @@ -60,6 +60,7 @@ dependencies { optional("org.springframework.data:spring-data-neo4j") optional("org.springframework.data:spring-data-redis") optional("org.springframework.data:spring-data-rest-webmvc") + optional("org.springframework.data:spring-data-elasticsearch") optional("org.springframework.data:spring-data-solr") optional("org.springframework.integration:spring-integration-core") optional("org.springframework.security:spring-security-core") diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchReactiveHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchReactiveHealthIndicator.java new file mode 100644 index 000000000000..10927dff5d9a --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchReactiveHealthIndicator.java @@ -0,0 +1,61 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.elasticsearch; + +import java.util.stream.Collectors; + +import reactor.core.publisher.Mono; + +import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient; + +/** + * {@link HealthIndicator} for an Elasticsearch cluster using a + * {@link ReactiveElasticsearchClient}. + * + * @author Aleksander Lech + * @since 2.3 + */ +public class ElasticsearchReactiveHealthIndicator extends AbstractReactiveHealthIndicator { + + private final ReactiveElasticsearchClient client; + + public ElasticsearchReactiveHealthIndicator(ReactiveElasticsearchClient client) { + super("Elasticsearch health check failed"); + this.client = client; + } + + @Override + protected Mono doHealthCheck(Health.Builder builder) { + return this.client.status().map((status) -> { + if (status.isOk()) { + builder.up(); + } + else { + builder.down(); + } + + builder.withDetails(status.hosts().stream().collect(Collectors + .toMap((host) -> host.getEndpoint().getHostString(), (host) -> host.getState().toString()))); + + return builder.build(); + }); + } + +}