Merge branch '2.1.x'

pull/15465/head
Brian Clozel 6 years ago
commit 9a6dbb5290

@ -16,14 +16,16 @@
package org.springframework.boot.actuate.elasticsearch; package org.springframework.boot.actuate.elasticsearch;
import com.google.gson.JsonElement; import java.util.Map;
import com.google.gson.JsonParser;
import io.searchbox.client.JestClient; import io.searchbox.client.JestClient;
import io.searchbox.client.JestResult; import io.searchbox.client.JestResult;
import org.springframework.boot.actuate.health.AbstractHealthIndicator; import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.json.JsonParser;
import org.springframework.boot.json.JsonParserFactory;
/** /**
* {@link HealthIndicator} for Elasticsearch using a {@link JestClient}. * {@link HealthIndicator} for Elasticsearch using a {@link JestClient}.
@ -37,7 +39,7 @@ public class ElasticsearchJestHealthIndicator extends AbstractHealthIndicator {
private final JestClient jestClient; private final JestClient jestClient;
private final JsonParser jsonParser = new JsonParser(); private final JsonParser jsonParser = JsonParserFactory.getJsonParser();
public ElasticsearchJestHealthIndicator(JestClient jestClient) { public ElasticsearchJestHealthIndicator(JestClient jestClient) {
super("Elasticsearch health check failed"); super("Elasticsearch health check failed");
@ -50,17 +52,19 @@ public class ElasticsearchJestHealthIndicator extends AbstractHealthIndicator {
.execute(new io.searchbox.cluster.Health.Builder().build()); .execute(new io.searchbox.cluster.Health.Builder().build());
if (healthResult.getResponseCode() != 200 || !healthResult.isSucceeded()) { if (healthResult.getResponseCode() != 200 || !healthResult.isSucceeded()) {
builder.down(); builder.down();
builder.withDetail("statusCode", healthResult.getResponseCode());
} }
else { else {
JsonElement root = this.jsonParser.parse(healthResult.getJsonString()); Map<String, Object> response = this.jsonParser
JsonElement status = root.getAsJsonObject().get("status"); .parseMap(healthResult.getJsonString());
if (status.getAsString() String status = (String) response.get("status");
.equals(io.searchbox.cluster.Health.Status.RED.getKey())) { if (status.equals(io.searchbox.cluster.Health.Status.RED.getKey())) {
builder.outOfService(); builder.outOfService();
} }
else { else {
builder.up(); builder.up();
} }
builder.withDetails(response);
} }
} }

@ -18,8 +18,10 @@ package org.springframework.boot.actuate.elasticsearch;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Map;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.elasticsearch.client.Request; import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response; import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClient;
@ -36,6 +38,7 @@ import org.springframework.util.StreamUtils;
* *
* @author Artsiom Yudovin * @author Artsiom Yudovin
* @author Brian Clozel * @author Brian Clozel
* @author Filip Hrisafov
* @since 2.1.1 * @since 2.1.1
*/ */
public class ElasticsearchRestHealthIndicator extends AbstractHealthIndicator { public class ElasticsearchRestHealthIndicator extends AbstractHealthIndicator {
@ -56,8 +59,11 @@ public class ElasticsearchRestHealthIndicator extends AbstractHealthIndicator {
protected void doHealthCheck(Health.Builder builder) throws Exception { protected void doHealthCheck(Health.Builder builder) throws Exception {
Response response = this.client Response response = this.client
.performRequest(new Request("GET", "/_cluster/health/")); .performRequest(new Request("GET", "/_cluster/health/"));
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { StatusLine statusLine = response.getStatusLine();
if (statusLine.getStatusCode() != HttpStatus.SC_OK) {
builder.down(); builder.down();
builder.withDetail("statusCode", statusLine.getStatusCode());
builder.withDetail("reasonPhrase", statusLine.getReasonPhrase());
return; return;
} }
try (InputStream inputStream = response.getEntity().getContent()) { try (InputStream inputStream = response.getEntity().getContent()) {
@ -67,12 +73,16 @@ public class ElasticsearchRestHealthIndicator extends AbstractHealthIndicator {
} }
private void doHealthCheck(Health.Builder builder, String json) { private void doHealthCheck(Health.Builder builder, String json) {
String status = (String) this.jsonParser.parseMap(json).get("status"); Map<String, Object> response = this.jsonParser.parseMap(json);
String status = (String) response.get("status");
if (RED_STATUS.equals(status)) { if (RED_STATUS.equals(status)) {
builder.outOfService(); builder.outOfService();
return;
} }
builder.up(); else {
builder.up();
}
builder.withDetails(response);
} }
} }

@ -17,6 +17,7 @@
package org.springframework.boot.actuate.elasticsearch; package org.springframework.boot.actuate.elasticsearch;
import java.io.IOException; import java.io.IOException;
import java.util.Map;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
@ -31,6 +32,7 @@ import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.Status; import org.springframework.boot.actuate.health.Status;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -56,6 +58,16 @@ public class ElasticsearchJestHealthIndicatorTests {
.willReturn(createJestResult(200, true, "green")); .willReturn(createJestResult(200, true, "green"));
Health health = this.healthIndicator.health(); Health health = this.healthIndicator.health();
assertThat(health.getStatus()).isEqualTo(Status.UP); assertThat(health.getStatus()).isEqualTo(Status.UP);
assertHealthDetailsWithStatus(health.getDetails(), "green");
}
@Test
public void elasticsearchWithYellowStatusIsUp() throws IOException {
given(this.jestClient.execute(any(Action.class)))
.willReturn(createJestResult(200, true, "yellow"));
Health health = this.healthIndicator.health();
assertThat(health.getStatus()).isEqualTo(Status.UP);
assertHealthDetailsWithStatus(health.getDetails(), "yellow");
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -83,6 +95,7 @@ public class ElasticsearchJestHealthIndicatorTests {
.willReturn(createJestResult(500, false, "")); .willReturn(createJestResult(500, false, ""));
Health health = this.healthIndicator.health(); Health health = this.healthIndicator.health();
assertThat(health.getStatus()).isEqualTo(Status.DOWN); assertThat(health.getStatus()).isEqualTo(Status.DOWN);
assertThat(health.getDetails()).contains(entry("statusCode", 500));
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -92,6 +105,21 @@ public class ElasticsearchJestHealthIndicatorTests {
.willReturn(createJestResult(200, true, "red")); .willReturn(createJestResult(200, true, "red"));
Health health = this.healthIndicator.health(); Health health = this.healthIndicator.health();
assertThat(health.getStatus()).isEqualTo(Status.OUT_OF_SERVICE); assertThat(health.getStatus()).isEqualTo(Status.OUT_OF_SERVICE);
assertHealthDetailsWithStatus(health.getDetails(), "red");
}
private void assertHealthDetailsWithStatus(Map<String, Object> details,
String status) {
assertThat(details).contains(entry("cluster_name", "elasticsearch"),
entry("status", status), entry("timed_out", false),
entry("number_of_nodes", 1), entry("number_of_data_nodes", 1),
entry("active_primary_shards", 0), entry("active_shards", 0),
entry("relocating_shards", 0), entry("initializing_shards", 0),
entry("unassigned_shards", 0), entry("delayed_unassigned_shards", 0),
entry("number_of_pending_tasks", 0),
entry("number_of_in_flight_fetch", 0),
entry("task_max_waiting_in_queue_millis", 0),
entry("active_shards_percent_as_number", 100.0));
} }
private static JestResult createJestResult(int responseCode, boolean succeeded, private static JestResult createJestResult(int responseCode, boolean succeeded,

@ -18,6 +18,7 @@ package org.springframework.boot.actuate.elasticsearch;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Map;
import org.apache.http.StatusLine; import org.apache.http.StatusLine;
import org.apache.http.entity.BasicHttpEntity; import org.apache.http.entity.BasicHttpEntity;
@ -26,9 +27,11 @@ import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClient;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.Status; import org.springframework.boot.actuate.health.Status;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.mock; import static org.mockito.BDDMockito.mock;
import static org.mockito.BDDMockito.when; import static org.mockito.BDDMockito.when;
@ -37,6 +40,7 @@ import static org.mockito.BDDMockito.when;
* Tests for {@link ElasticsearchRestHealthIndicator}. * Tests for {@link ElasticsearchRestHealthIndicator}.
* *
* @author Artsiom Yudovin * @author Artsiom Yudovin
* @author Filip Hrisafov
*/ */
public class ElasticsearchRestHealthIndicatorTest { public class ElasticsearchRestHealthIndicatorTest {
@ -59,8 +63,28 @@ public class ElasticsearchRestHealthIndicatorTest {
when(response.getEntity()).thenReturn(httpEntity); when(response.getEntity()).thenReturn(httpEntity);
when(this.restClient.performRequest(any(Request.class))).thenReturn(response); when(this.restClient.performRequest(any(Request.class))).thenReturn(response);
assertThat(this.elasticsearchRestHealthIndicator.health().getStatus()) Health health = this.elasticsearchRestHealthIndicator.health();
.isEqualTo(Status.UP); assertThat(health.getStatus()).isEqualTo(Status.UP);
assertHealthDetailsWithStatus(health.getDetails(), "green");
}
@Test
public void elasticsearchWithYellowStatusIsUp() throws IOException {
BasicHttpEntity httpEntity = new BasicHttpEntity();
httpEntity.setContent(
new ByteArrayInputStream(createJsonResult(200, "yellow").getBytes()));
Response response = mock(Response.class);
StatusLine statusLine = mock(StatusLine.class);
when(statusLine.getStatusCode()).thenReturn(200);
when(response.getStatusLine()).thenReturn(statusLine);
when(response.getEntity()).thenReturn(httpEntity);
when(this.restClient.performRequest(any(Request.class))).thenReturn(response);
Health health = this.elasticsearchRestHealthIndicator.health();
assertThat(health.getStatus()).isEqualTo(Status.UP);
assertHealthDetailsWithStatus(health.getDetails(), "yellow");
} }
@Test @Test
@ -68,22 +92,26 @@ public class ElasticsearchRestHealthIndicatorTest {
when(this.restClient.performRequest(any(Request.class))) when(this.restClient.performRequest(any(Request.class)))
.thenThrow(new IOException("Couldn't connect")); .thenThrow(new IOException("Couldn't connect"));
assertThat(this.elasticsearchRestHealthIndicator.health().getStatus()) Health health = this.elasticsearchRestHealthIndicator.health();
.isEqualTo(Status.DOWN); assertThat(health.getStatus()).isEqualTo(Status.DOWN);
assertThat(health.getDetails())
.contains(entry("error", "java.io.IOException: Couldn't connect"));
} }
@Test @Test
public void elasticsearchIsDownByResponseCode() throws IOException { public void elasticsearchIsDownByResponseCode() throws IOException {
Response response = mock(Response.class); Response response = mock(Response.class);
StatusLine statusLine = mock(StatusLine.class); StatusLine statusLine = mock(StatusLine.class);
when(statusLine.getStatusCode()).thenReturn(500); when(statusLine.getStatusCode()).thenReturn(500);
when(statusLine.getReasonPhrase()).thenReturn("Internal server error");
when(response.getStatusLine()).thenReturn(statusLine); when(response.getStatusLine()).thenReturn(statusLine);
when(this.restClient.performRequest(any(Request.class))).thenReturn(response); when(this.restClient.performRequest(any(Request.class))).thenReturn(response);
assertThat(this.elasticsearchRestHealthIndicator.health().getStatus()) Health health = this.elasticsearchRestHealthIndicator.health();
.isEqualTo(Status.DOWN); assertThat(health.getStatus()).isEqualTo(Status.DOWN);
assertThat(health.getDetails()).contains(entry("statusCode", 500),
entry("reasonPhrase", "Internal server error"));
} }
@Test @Test
@ -100,8 +128,23 @@ public class ElasticsearchRestHealthIndicatorTest {
when(response.getEntity()).thenReturn(httpEntity); when(response.getEntity()).thenReturn(httpEntity);
when(this.restClient.performRequest(any(Request.class))).thenReturn(response); when(this.restClient.performRequest(any(Request.class))).thenReturn(response);
assertThat(this.elasticsearchRestHealthIndicator.health().getStatus()) Health health = this.elasticsearchRestHealthIndicator.health();
.isEqualTo(Status.OUT_OF_SERVICE); assertThat(health.getStatus()).isEqualTo(Status.OUT_OF_SERVICE);
assertHealthDetailsWithStatus(health.getDetails(), "red");
}
private void assertHealthDetailsWithStatus(Map<String, Object> details,
String status) {
assertThat(details).contains(entry("cluster_name", "elasticsearch"),
entry("status", status), entry("timed_out", false),
entry("number_of_nodes", 1), entry("number_of_data_nodes", 1),
entry("active_primary_shards", 0), entry("active_shards", 0),
entry("relocating_shards", 0), entry("initializing_shards", 0),
entry("unassigned_shards", 0), entry("delayed_unassigned_shards", 0),
entry("number_of_pending_tasks", 0),
entry("number_of_in_flight_fetch", 0),
entry("task_max_waiting_in_queue_millis", 0),
entry("active_shards_percent_as_number", 100.0));
} }
private String createJsonResult(int responseCode, String status) { private String createJsonResult(int responseCode, String status) {

Loading…
Cancel
Save