diff --git a/spring-boot-actuator/.gitignore b/spring-boot-actuator/.gitignore
new file mode 100644
index 0000000000..3af0ccb687
--- /dev/null
+++ b/spring-boot-actuator/.gitignore
@@ -0,0 +1 @@
+/data
diff --git a/spring-boot-actuator/pom.xml b/spring-boot-actuator/pom.xml
index e58f54bded..924506687e 100644
--- a/spring-boot-actuator/pom.xml
+++ b/spring-boot-actuator/pom.xml
@@ -97,8 +97,8 @@
true
- org.springframework.data
- spring-data-elasticsearch
+ org.elasticsearch
+ elasticsearch
true
@@ -173,35 +173,40 @@
true
+
+ org.springframework.boot
+ spring-boot
+ test-jar
+ test
+
ch.qos.logback
logback-classic
test
+
+ org.apache.tomcat.embed
+ tomcat-embed-logging-juli
+ test
+
org.crashub
crash.connectors.telnet
test
-
- org.springframework
- spring-test
- test
-
org.hsqldb
hsqldb
test
- org.springframework.boot
- spring-boot
- test-jar
+ org.springframework
+ spring-test
test
- org.apache.tomcat.embed
- tomcat-embed-logging-juli
+ org.springframework.data
+ spring-data-elasticsearch
test
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ElasticsearchHealthIndicatorConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ElasticsearchHealthIndicatorConfiguration.java
deleted file mode 100644
index 2f934bf3dd..0000000000
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ElasticsearchHealthIndicatorConfiguration.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2014 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
- *
- * http://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;
-
-import org.elasticsearch.client.Client;
-import org.springframework.boot.actuate.health.ElasticsearchHealthIndicator;
-import org.springframework.boot.actuate.health.ElasticsearchHealthIndicatorProperties;
-import org.springframework.boot.actuate.health.HealthIndicator;
-import org.springframework.boot.autoconfigure.AutoConfigureAfter;
-import org.springframework.boot.autoconfigure.AutoConfigureBefore;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-/**
- * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration Auto-configuration} for
- * {@link org.springframework.boot.actuate.health.ElasticsearchHealthIndicator}.
- *
- * @author Binwei Yang
- * @since 1.2.2
- */
-@Configuration
-@AutoConfigureBefore({EndpointAutoConfiguration.class})
-@AutoConfigureAfter({HealthIndicatorAutoConfiguration.class})
-@ConditionalOnProperty(prefix = "management.health.elasticsearch", name = "enabled", matchIfMissing = true)
-public class ElasticsearchHealthIndicatorConfiguration {
-
- @Bean
- @ConditionalOnBean(Client.class)
- @ConditionalOnMissingBean(name = "elasticsearchHealthIndicator")
- public HealthIndicator elasticsearchHealthIndicator() {
- return new ElasticsearchHealthIndicator();
- }
-
- @Bean
- public ElasticsearchHealthIndicatorProperties elasticsearchHealthIndicatorProperties() {
- return new ElasticsearchHealthIndicatorProperties();
- }
-}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java
index 7a1790e17f..518444f3bb 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java
@@ -23,6 +23,7 @@ import javax.jms.ConnectionFactory;
import javax.sql.DataSource;
import org.apache.solr.client.solrj.SolrServer;
+import org.elasticsearch.client.Client;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
@@ -31,6 +32,8 @@ import org.springframework.boot.actuate.health.CompositeHealthIndicator;
import org.springframework.boot.actuate.health.DataSourceHealthIndicator;
import org.springframework.boot.actuate.health.DiskSpaceHealthIndicator;
import org.springframework.boot.actuate.health.DiskSpaceHealthIndicatorProperties;
+import org.springframework.boot.actuate.health.ElasticsearchHealthIndicator;
+import org.springframework.boot.actuate.health.ElasticsearchHealthIndicatorProperties;
import org.springframework.boot.actuate.health.HealthAggregator;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.actuate.health.JmsHealthIndicator;
@@ -47,6 +50,7 @@ import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadata;
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvider;
@@ -79,7 +83,8 @@ import org.springframework.mail.javamail.JavaMailSenderImpl;
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, MongoAutoConfiguration.class,
MongoDataAutoConfiguration.class, RedisAutoConfiguration.class,
RabbitAutoConfiguration.class, SolrAutoConfiguration.class,
- MailSenderAutoConfiguration.class, JmsAutoConfiguration.class })
+ MailSenderAutoConfiguration.class, JmsAutoConfiguration.class,
+ ElasticsearchAutoConfiguration.class })
@EnableConfigurationProperties({ HealthIndicatorAutoConfigurationProperties.class })
public class HealthIndicatorAutoConfiguration {
@@ -306,4 +311,30 @@ public class HealthIndicatorAutoConfiguration {
}
+ @Configuration
+ @ConditionalOnBean(Client.class)
+ @ConditionalOnProperty(prefix = "management.health.elasticsearch", name = "enabled", matchIfMissing = true)
+ @EnableConfigurationProperties(ElasticsearchHealthIndicatorProperties.class)
+ public static class ElasticsearchHealthIndicatorConfiguration extends
+ CompositeHealthIndicatorConfiguration {
+
+ @Autowired
+ private Map clients;
+
+ @Autowired
+ private ElasticsearchHealthIndicatorProperties properties;
+
+ @Bean
+ @ConditionalOnMissingBean(name = "elasticsearchHealthIndicator")
+ public HealthIndicator elasticsearchHealthIndicator() {
+ return createHealthIndicator(this.clients);
+ }
+
+ @Override
+ protected ElasticsearchHealthIndicator createHealthIndicator(Client client) {
+ return new ElasticsearchHealthIndicator(client, this.properties);
+ }
+
+ }
+
}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ElasticsearchHealthIndicator.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ElasticsearchHealthIndicator.java
index 9c062bbab0..55b424d64d 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ElasticsearchHealthIndicator.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ElasticsearchHealthIndicator.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 the original author or authors.
+ * Copyright 2012-2015 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.
@@ -16,47 +16,58 @@
package org.springframework.boot.actuate.health;
+import java.util.List;
+
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.Requests;
-import org.springframework.beans.factory.annotation.Autowired;
/**
- * Simple implementation of a {@link HealthIndicator} returning health status information for
- * ElasticSearch cluster.
+ * {@link HealthIndicator} for an Elasticsearch cluster.
*
* @author Binwei Yang
- * @since 1.2.2
+ * @author Andy Wilkinson
+ * @since 1.3.0
*/
-public class ElasticsearchHealthIndicator extends ApplicationHealthIndicator {
- @Autowired
- private Client client;
+public class ElasticsearchHealthIndicator extends AbstractHealthIndicator {
- @Autowired
- private ElasticsearchHealthIndicatorProperties properties;
+ private final Client client;
- @Override
- protected void doHealthCheck(Health.Builder builder) throws Exception {
- try {
- ClusterHealthResponse response = client.admin().cluster().health(Requests.clusterHealthRequest(
- properties.getIndexNamesAsArray()
- )).actionGet(100);
+ private final ElasticsearchHealthIndicatorProperties properties;
- switch (response.getStatus()) {
- case GREEN:
- builder.up();
- break;
- case RED:
- builder.down();
- break;
- case YELLOW:
- default:
- builder.unknown();
- break;
- }
- builder.withDetail("clusterHealth", response);
- } catch (Exception handled) {
- builder.unknown().withDetail("exception", handled);
- }
- }
+ public ElasticsearchHealthIndicator(Client client,
+ ElasticsearchHealthIndicatorProperties properties) {
+ this.client = client;
+ this.properties = properties;
+ }
+
+ @Override
+ protected void doHealthCheck(Health.Builder builder) throws Exception {
+ List indices = this.properties.getIndices();
+ ClusterHealthResponse response = this.client
+ .admin()
+ .cluster()
+ .health(Requests.clusterHealthRequest(indices.isEmpty() ? null : indices
+ .toArray(new String[indices.size()])))
+ .actionGet(this.properties.getResponseTimeout());
+
+ switch (response.getStatus()) {
+ case GREEN:
+ case YELLOW:
+ builder.up();
+ break;
+ case RED:
+ default:
+ builder.down();
+ break;
+ }
+ builder.withDetail("clusterName", response.getClusterName());
+ builder.withDetail("numberOfNodes", response.getNumberOfNodes());
+ builder.withDetail("numberOfDataNodes", response.getNumberOfDataNodes());
+ builder.withDetail("activePrimaryShards", response.getActivePrimaryShards());
+ builder.withDetail("activeShards", response.getActiveShards());
+ builder.withDetail("relocatingShards", response.getRelocatingShards());
+ builder.withDetail("initializingShards", response.getInitializingShards());
+ builder.withDetail("unassignedShards", response.getUnassignedShards());
+ }
}
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ElasticsearchHealthIndicatorProperties.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ElasticsearchHealthIndicatorProperties.java
index c0b10aa46a..2c52c8c865 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ElasticsearchHealthIndicatorProperties.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ElasticsearchHealthIndicatorProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 the original author or authors.
+ * Copyright 2012-2015 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.
@@ -16,37 +16,41 @@
package org.springframework.boot.actuate.health;
+import java.util.ArrayList;
+import java.util.List;
+
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* External configuration properties for {@link ElasticsearchHealthIndicator}
*
* @author Binwei Yang
- * @since 1.2.2
+ * @author Andy Wilkinson
+ * @since 1.3.0
*/
@ConfigurationProperties("management.health.elasticsearch")
public class ElasticsearchHealthIndicatorProperties {
- public static final String ALL = "_all";
+ /**
+ * Comma-separated index names
+ */
+ private List indices = new ArrayList();
- /**
- * comma separated index names. the default includes all indices.
- */
- private String indices = ALL;
+ /**
+ * The time, in milliseconds, to wait for a response from the cluster
+ */
+ private long responseTimeout = 100L;
- public String getIndices() {
- return indices;
- }
+ public List getIndices() {
+ return this.indices;
+ }
- public void setIndices(String indices) {
- this.indices = indices;
- }
+ public long getResponseTimeout() {
+ return this.responseTimeout;
+ }
+
+ public void setResponseTimeout(long responseTimeout) {
+ this.responseTimeout = responseTimeout;
+ }
- String[] getIndexNamesAsArray() {
- if (null == indices) {
- return new String[]{ALL};
- } else {
- return indices.split(",");
- }
- }
}
diff --git a/spring-boot-actuator/src/main/resources/META-INF/spring.factories b/spring-boot-actuator/src/main/resources/META-INF/spring.factories
index 52b28beda8..6d4f6a7867 100644
--- a/spring-boot-actuator/src/main/resources/META-INF/spring.factories
+++ b/spring-boot-actuator/src/main/resources/META-INF/spring.factories
@@ -12,5 +12,4 @@ org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.MetricRepositoryAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.PublicMetricsAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.TraceRepositoryAutoConfiguration,\
-org.springframework.boot.actuate.autoconfigure.TraceWebFilterAutoConfiguration,\
-org.springframework.boot.actuate.autoconfigure.ElasticsearchHealthIndicatorConfiguration
+org.springframework.boot.actuate.autoconfigure.TraceWebFilterAutoConfiguration
\ No newline at end of file
diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java
index 251214a9aa..91171bbf06 100644
--- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java
+++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java
@@ -26,6 +26,7 @@ import org.junit.Test;
import org.springframework.boot.actuate.health.ApplicationHealthIndicator;
import org.springframework.boot.actuate.health.DataSourceHealthIndicator;
import org.springframework.boot.actuate.health.DiskSpaceHealthIndicator;
+import org.springframework.boot.actuate.health.ElasticsearchHealthIndicator;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.actuate.health.JmsHealthIndicator;
import org.springframework.boot.actuate.health.MailHealthIndicator;
@@ -35,6 +36,7 @@ import org.springframework.boot.actuate.health.RedisHealthIndicator;
import org.springframework.boot.actuate.health.SolrHealthIndicator;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;
+import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
@@ -59,6 +61,7 @@ import static org.junit.Assert.assertEquals;
*
* @author Christian Dupuis
* @author Stephane Nicoll
+ * @author Andy Wilkinson
*/
public class HealthIndicatorAutoConfigurationTests {
@@ -362,6 +365,39 @@ public class HealthIndicatorAutoConfigurationTests {
.getClass());
}
+ @Test
+ public void elasticSearchHealthIndicator() {
+ this.context = new AnnotationConfigApplicationContext();
+ EnvironmentTestUtils.addEnvironment(this.context,
+ "management.health.diskspace.enabled:false");
+ this.context.register(ElasticsearchAutoConfiguration.class,
+ ManagementServerProperties.class, HealthIndicatorAutoConfiguration.class);
+ this.context.refresh();
+
+ Map beans = this.context
+ .getBeansOfType(HealthIndicator.class);
+ assertEquals(1, beans.size());
+ assertEquals(ElasticsearchHealthIndicator.class, beans.values().iterator().next()
+ .getClass());
+ }
+
+ @Test
+ public void notElasticSearchHealthIndicator() {
+ this.context = new AnnotationConfigApplicationContext();
+ EnvironmentTestUtils.addEnvironment(this.context,
+ "management.health.elasticsearch.enabled:false",
+ "management.health.diskspace.enabled:false");
+ this.context.register(ElasticsearchAutoConfiguration.class,
+ ManagementServerProperties.class, HealthIndicatorAutoConfiguration.class);
+ this.context.refresh();
+
+ Map beans = this.context
+ .getBeansOfType(HealthIndicator.class);
+ assertEquals(1, beans.size());
+ assertEquals(ApplicationHealthIndicator.class, beans.values().iterator().next()
+ .getClass());
+ }
+
@Configuration
@EnableConfigurationProperties
protected static class DataSourceConfig {
diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ElasticsearchHealthIndicatorTest.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ElasticsearchHealthIndicatorTest.java
deleted file mode 100644
index 2f59537f89..0000000000
--- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ElasticsearchHealthIndicatorTest.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2014 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
- *
- * http://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.health;
-
-import org.elasticsearch.client.Client;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.springframework.boot.actuate.autoconfigure.ElasticsearchHealthIndicatorConfiguration;
-import org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration;
-import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
-import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchAutoConfiguration;
-import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchDataAutoConfiguration;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-/**
- * Test for {@link ElasticsearchHealthIndicator} for ElasticSearch cluster.
- *
- * @author Binwei Yang
- * @since 1.2.2
- */
-public class ElasticsearchHealthIndicatorTest {
- private AnnotationConfigApplicationContext context;
-
- @Before
- public void setUp() throws Exception {
- this.context = new AnnotationConfigApplicationContext(
- PropertyPlaceholderAutoConfiguration.class,
- ElasticsearchAutoConfiguration.class,
- ElasticsearchDataAutoConfiguration.class,
- EndpointAutoConfiguration.class,
- ElasticsearchHealthIndicatorConfiguration.class
- );
- }
-
- @After
- public void close() {
- if (null != context) {
- context.close();
- }
- }
-
- @Test
- public void indicatorExists() {
- assertEquals(1, this.context.getBeanNamesForType(Client.class).length);
-
- ElasticsearchHealthIndicator healthIndicator = this.context.getBean(ElasticsearchHealthIndicator.class);
- assertNotNull(healthIndicator);
- }
-
- @Test
- public void configPropertiesUsed() {
- ElasticsearchHealthIndicatorProperties properties = this.context.getBean(ElasticsearchHealthIndicatorProperties.class);
-
- // test default index
- assertEquals(ElasticsearchHealthIndicatorProperties.ALL, properties.getIndices());
- assertEquals(1, properties.getIndexNamesAsArray().length);
- assertEquals(ElasticsearchHealthIndicatorProperties.ALL, properties.getIndexNamesAsArray()[0]);
-
- // test specific indices
- properties.setIndices("no-such-index");
-
- ElasticsearchHealthIndicator healthIndicator = this.context.getBean(ElasticsearchHealthIndicator.class);
- Health health = healthIndicator.health();
- assertEquals(Status.UNKNOWN, health.getStatus());
- }
-}
diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ElasticsearchHealthIndicatorTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ElasticsearchHealthIndicatorTests.java
new file mode 100644
index 0000000000..611ca1086f
--- /dev/null
+++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ElasticsearchHealthIndicatorTests.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2012-2015 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
+ *
+ * http://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.health;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import org.elasticsearch.ElasticsearchException;
+import org.elasticsearch.ElasticsearchTimeoutException;
+import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
+import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
+import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus;
+import org.elasticsearch.action.support.PlainActionFuture;
+import org.elasticsearch.client.AdminClient;
+import org.elasticsearch.client.Client;
+import org.elasticsearch.client.ClusterAdminClient;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import static org.hamcrest.Matchers.arrayContaining;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertThat;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Matchers.any;
+
+/**
+ * Test for {@link ElasticsearchHealthIndicator}.
+ *
+ * @author Andy Wilkinson
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class ElasticsearchHealthIndicatorTests {
+
+ @Mock
+ private Client client;
+
+ @Mock
+ private AdminClient admin;
+
+ @Mock
+ private ClusterAdminClient cluster;
+
+ private ElasticsearchHealthIndicator indicator;
+
+ private ElasticsearchHealthIndicatorProperties properties = new ElasticsearchHealthIndicatorProperties();
+
+ @Before
+ public void setUp() throws Exception {
+ given(this.client.admin()).willReturn(this.admin);
+ given(this.admin.cluster()).willReturn(this.cluster);
+
+ this.indicator = new ElasticsearchHealthIndicator(this.client, this.properties);
+ }
+
+ @Test
+ public void defaultConfigurationQueriesAllIndicesWith100msTimeout() {
+ TestActionFuture responseFuture = new TestActionFuture();
+ responseFuture.onResponse(new StubClusterHealthResponse());
+ ArgumentCaptor requestCaptor = ArgumentCaptor
+ .forClass(ClusterHealthRequest.class);
+ given(this.cluster.health(requestCaptor.capture())).willReturn(responseFuture);
+ Health health = this.indicator.health();
+ assertThat(responseFuture.getTimeout, is(100L));
+ assertThat(requestCaptor.getValue().indices(), is(nullValue()));
+ assertThat(health.getStatus(), is(Status.UP));
+ }
+
+ @Test
+ public void certainIndices() {
+ PlainActionFuture responseFuture = new PlainActionFuture();
+ responseFuture.onResponse(new StubClusterHealthResponse());
+ ArgumentCaptor requestCaptor = ArgumentCaptor
+ .forClass(ClusterHealthRequest.class);
+ given(this.cluster.health(requestCaptor.capture())).willReturn(responseFuture);
+ this.properties.getIndices()
+ .addAll(Arrays.asList("test-index-1", "test-index-2"));
+ Health health = this.indicator.health();
+ assertThat(requestCaptor.getValue().indices(),
+ is(arrayContaining("test-index-1", "test-index-2")));
+ assertThat(health.getStatus(), is(Status.UP));
+ }
+
+ @Test
+ public void customTimeout() {
+ TestActionFuture responseFuture = new TestActionFuture();
+ responseFuture.onResponse(new StubClusterHealthResponse());
+ ArgumentCaptor requestCaptor = ArgumentCaptor
+ .forClass(ClusterHealthRequest.class);
+ given(this.cluster.health(requestCaptor.capture())).willReturn(responseFuture);
+ this.properties.setResponseTimeout(1000L);
+ this.indicator.health();
+ assertThat(responseFuture.getTimeout, is(1000L));
+ }
+
+ @Test
+ public void healthDetails() {
+ PlainActionFuture responseFuture = new PlainActionFuture();
+ responseFuture.onResponse(new StubClusterHealthResponse());
+ given(this.cluster.health(any(ClusterHealthRequest.class))).willReturn(
+ responseFuture);
+ Health health = this.indicator.health();
+ assertThat(health.getStatus(), is(Status.UP));
+ Map details = health.getDetails();
+ assertDetail(details, "clusterName", "test-cluster");
+ assertDetail(details, "activeShards", 1);
+ assertDetail(details, "relocatingShards", 2);
+ assertDetail(details, "activePrimaryShards", 3);
+ assertDetail(details, "initializingShards", 4);
+ assertDetail(details, "unassignedShards", 5);
+ assertDetail(details, "numberOfNodes", 6);
+ assertDetail(details, "numberOfDataNodes", 7);
+ }
+
+ @Test
+ public void redResponseMapsToDown() {
+ PlainActionFuture responseFuture = new PlainActionFuture();
+ responseFuture.onResponse(new StubClusterHealthResponse(ClusterHealthStatus.RED));
+ given(this.cluster.health(any(ClusterHealthRequest.class))).willReturn(
+ responseFuture);
+ assertThat(this.indicator.health().getStatus(), is(Status.DOWN));
+ }
+
+ @Test
+ public void yellowResponseMapsToUp() {
+ PlainActionFuture responseFuture = new PlainActionFuture();
+ responseFuture.onResponse(new StubClusterHealthResponse(
+ ClusterHealthStatus.YELLOW));
+ given(this.cluster.health(any(ClusterHealthRequest.class))).willReturn(
+ responseFuture);
+ assertThat(this.indicator.health().getStatus(), is(Status.UP));
+ }
+
+ @Test
+ public void responseTimeout() {
+ PlainActionFuture responseFuture = new PlainActionFuture();
+ given(this.cluster.health(any(ClusterHealthRequest.class))).willReturn(
+ responseFuture);
+ Health health = this.indicator.health();
+ assertThat(health.getStatus(), is(Status.DOWN));
+ assertThat((String) health.getDetails().get("error"),
+ containsString(ElasticsearchTimeoutException.class.getName()));
+ }
+
+ @SuppressWarnings("unchecked")
+ private void assertDetail(Map details, String detail, T value) {
+ assertThat((T) details.get(detail), is(equalTo(value)));
+ }
+
+ private static class StubClusterHealthResponse extends ClusterHealthResponse {
+
+ private final ClusterHealthStatus status;
+
+ private StubClusterHealthResponse() {
+ this(ClusterHealthStatus.GREEN);
+ }
+
+ private StubClusterHealthResponse(ClusterHealthStatus status) {
+ super("test-cluster", null);
+ this.status = status;
+ }
+
+ @Override
+ public int getActiveShards() {
+ return 1;
+ }
+
+ @Override
+ public int getRelocatingShards() {
+ return 2;
+ }
+
+ @Override
+ public int getActivePrimaryShards() {
+ return 3;
+ }
+
+ @Override
+ public int getInitializingShards() {
+ return 4;
+ }
+
+ @Override
+ public int getUnassignedShards() {
+ return 5;
+ }
+
+ @Override
+ public int getNumberOfNodes() {
+ return 6;
+ }
+
+ @Override
+ public int getNumberOfDataNodes() {
+ return 7;
+ }
+
+ @Override
+ public ClusterHealthStatus getStatus() {
+ return this.status;
+ }
+
+ }
+
+ private static class TestActionFuture extends
+ PlainActionFuture {
+
+ private long getTimeout = -1L;
+
+ @Override
+ public ClusterHealthResponse actionGet(long timeoutMillis)
+ throws ElasticsearchException {
+ this.getTimeout = timeoutMillis;
+ return super.actionGet(timeoutMillis);
+ }
+
+ }
+}
diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml
index 7fb6ae32c1..a32ec83c1b 100644
--- a/spring-boot-dependencies/pom.xml
+++ b/spring-boot-dependencies/pom.xml
@@ -63,6 +63,7 @@
2.9.1
3.2
2.3.22
+ 1.4.4
7.0.2
3.0.0
1.12
@@ -1084,6 +1085,11 @@
websocket-server
${jetty.version}
+
+ org.elasticsearch
+ elasticsearch
+ ${elasticsearch.version}
+
org.flywaydb
flyway-core
diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
index 5714f57996..31bb2ab0f3 100644
--- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
+++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
@@ -542,13 +542,15 @@ content into your application; rather pick only the properties that you need.
# HEALTH INDICATORS (previously health.*)
management.health.db.enabled=true
+ management.health.elasticsearch.enabled=true
+ management.health.elasticsearch.response-timeout=100 # the time, in milliseconds, to wait for a response from the cluster
management.health.diskspace.enabled=true
+ management.health.diskspace.path=.
+ management.health.diskspace.threshold=10485760
management.health.mongo.enabled=true
management.health.rabbit.enabled=true
management.health.redis.enabled=true
management.health.solr.enabled=true
- management.health.diskspace.path=.
- management.health.diskspace.threshold=10485760
management.health.status.order=DOWN, OUT_OF_SERVICE, UNKNOWN, UP
# MVC ONLY ENDPOINTS