13 changed files with 88 additions and 384 deletions
@ -1,69 +0,0 @@
@@ -1,69 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2022 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 org.elasticsearch.client.RestClient; |
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration; |
||||
import org.springframework.boot.actuate.elasticsearch.ElasticsearchRestClientHealthIndicator; |
||||
import org.springframework.boot.actuate.health.HealthContributor; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
|
||||
/** |
||||
* Elasticsearch rest client health contributor configurations. |
||||
* |
||||
* @author Filip Hrisafov |
||||
*/ |
||||
class ElasticSearchRestHealthContributorConfigurations { |
||||
|
||||
@Configuration(proxyBeanMethods = false) |
||||
@ConditionalOnClass(org.elasticsearch.client.RestHighLevelClient.class) |
||||
@ConditionalOnBean(org.elasticsearch.client.RestHighLevelClient.class) |
||||
@Deprecated |
||||
static class RestHighLevelClientHealthContributorConfiguration extends |
||||
CompositeHealthContributorConfiguration<org.springframework.boot.actuate.elasticsearch.ElasticsearchRestHealthIndicator, org.elasticsearch.client.RestHighLevelClient> { |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean(name = { "elasticsearchHealthIndicator", "elasticsearchHealthContributor" }) |
||||
HealthContributor elasticsearchHealthContributor( |
||||
Map<String, org.elasticsearch.client.RestHighLevelClient> clients) { |
||||
return createContributor(clients); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration(proxyBeanMethods = false) |
||||
@ConditionalOnBean(RestClient.class) |
||||
@ConditionalOnMissingBean(org.elasticsearch.client.RestHighLevelClient.class) |
||||
static class RestClientHealthContributorConfiguration |
||||
extends CompositeHealthContributorConfiguration<ElasticsearchRestClientHealthIndicator, RestClient> { |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean(name = { "elasticsearchHealthIndicator", "elasticsearchHealthContributor" }) |
||||
HealthContributor elasticsearchHealthContributor(Map<String, RestClient> clients) { |
||||
return createContributor(clients); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
22
spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticsearchRestHealthContributorAutoConfigurationTests.java → spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchRestHealthContributorAutoConfigurationTests.java
22
spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticsearchRestHealthContributorAutoConfigurationTests.java → spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchRestHealthContributorAutoConfigurationTests.java
@ -1,85 +0,0 @@
@@ -1,85 +0,0 @@
|
||||
/* |
||||
* 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.io.InputStream; |
||||
import java.nio.charset.StandardCharsets; |
||||
import java.util.Map; |
||||
|
||||
import org.apache.http.HttpStatus; |
||||
import org.apache.http.StatusLine; |
||||
import org.elasticsearch.client.Request; |
||||
import org.elasticsearch.client.Response; |
||||
import org.elasticsearch.client.RestClient; |
||||
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator; |
||||
import org.springframework.boot.actuate.health.Health; |
||||
import org.springframework.boot.actuate.health.HealthIndicator; |
||||
import org.springframework.boot.json.JsonParser; |
||||
import org.springframework.boot.json.JsonParserFactory; |
||||
import org.springframework.util.StreamUtils; |
||||
|
||||
/** |
||||
* {@link HealthIndicator} for an Elasticsearch cluster using a {@link RestClient}. |
||||
* |
||||
* @author Artsiom Yudovin |
||||
* @author Brian Clozel |
||||
* @author Filip Hrisafov |
||||
* @since 2.7 |
||||
*/ |
||||
public class ElasticsearchRestClientHealthIndicator extends AbstractHealthIndicator { |
||||
|
||||
private static final String RED_STATUS = "red"; |
||||
|
||||
private final RestClient client; |
||||
|
||||
private final JsonParser jsonParser; |
||||
|
||||
public ElasticsearchRestClientHealthIndicator(RestClient client) { |
||||
super("Elasticsearch health check failed"); |
||||
this.client = client; |
||||
this.jsonParser = JsonParserFactory.getJsonParser(); |
||||
} |
||||
|
||||
@Override |
||||
protected void doHealthCheck(Health.Builder builder) throws Exception { |
||||
Response response = this.client.performRequest(new Request("GET", "/_cluster/health/")); |
||||
StatusLine statusLine = response.getStatusLine(); |
||||
if (statusLine.getStatusCode() != HttpStatus.SC_OK) { |
||||
builder.down(); |
||||
builder.withDetail("statusCode", statusLine.getStatusCode()); |
||||
builder.withDetail("reasonPhrase", statusLine.getReasonPhrase()); |
||||
return; |
||||
} |
||||
try (InputStream inputStream = response.getEntity().getContent()) { |
||||
doHealthCheck(builder, StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8)); |
||||
} |
||||
} |
||||
|
||||
private void doHealthCheck(Health.Builder builder, String json) { |
||||
Map<String, Object> response = this.jsonParser.parseMap(json); |
||||
String status = (String) response.get("status"); |
||||
if (RED_STATUS.equals(status)) { |
||||
builder.outOfService(); |
||||
} |
||||
else { |
||||
builder.up(); |
||||
} |
||||
builder.withDetails(response); |
||||
} |
||||
|
||||
} |
||||
@ -1,143 +0,0 @@
@@ -1,143 +0,0 @@
|
||||
/* |
||||
* Copyright 2012-2019 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.io.ByteArrayInputStream; |
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
|
||||
import org.apache.http.StatusLine; |
||||
import org.apache.http.entity.BasicHttpEntity; |
||||
import org.elasticsearch.client.Request; |
||||
import org.elasticsearch.client.Response; |
||||
import org.elasticsearch.client.RestClient; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.boot.actuate.health.Health; |
||||
import org.springframework.boot.actuate.health.Status; |
||||
|
||||
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.BDDMockito.given; |
||||
import static org.mockito.Mockito.mock; |
||||
|
||||
/** |
||||
* Tests for {@link ElasticsearchRestClientHealthIndicator}. |
||||
* |
||||
* @author Artsiom Yudovin |
||||
* @author Filip Hrisafov |
||||
*/ |
||||
class ElasticsearchRestClientHealthIndicatorTests { |
||||
|
||||
private final RestClient restClient = mock(RestClient.class); |
||||
|
||||
private final ElasticsearchRestClientHealthIndicator elasticsearchRestHealthIndicator = new ElasticsearchRestClientHealthIndicator( |
||||
this.restClient); |
||||
|
||||
@Test |
||||
void elasticsearchIsUp() throws IOException { |
||||
BasicHttpEntity httpEntity = new BasicHttpEntity(); |
||||
httpEntity.setContent(new ByteArrayInputStream(createJsonResult(200, "green").getBytes())); |
||||
Response response = mock(Response.class); |
||||
StatusLine statusLine = mock(StatusLine.class); |
||||
given(statusLine.getStatusCode()).willReturn(200); |
||||
given(response.getStatusLine()).willReturn(statusLine); |
||||
given(response.getEntity()).willReturn(httpEntity); |
||||
given(this.restClient.performRequest(any(Request.class))).willReturn(response); |
||||
Health health = this.elasticsearchRestHealthIndicator.health(); |
||||
assertThat(health.getStatus()).isEqualTo(Status.UP); |
||||
assertHealthDetailsWithStatus(health.getDetails(), "green"); |
||||
} |
||||
|
||||
@Test |
||||
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); |
||||
given(statusLine.getStatusCode()).willReturn(200); |
||||
given(response.getStatusLine()).willReturn(statusLine); |
||||
given(response.getEntity()).willReturn(httpEntity); |
||||
given(this.restClient.performRequest(any(Request.class))).willReturn(response); |
||||
Health health = this.elasticsearchRestHealthIndicator.health(); |
||||
assertThat(health.getStatus()).isEqualTo(Status.UP); |
||||
assertHealthDetailsWithStatus(health.getDetails(), "yellow"); |
||||
} |
||||
|
||||
@Test |
||||
void elasticsearchIsDown() throws IOException { |
||||
given(this.restClient.performRequest(any(Request.class))).willThrow(new IOException("Couldn't connect")); |
||||
Health health = this.elasticsearchRestHealthIndicator.health(); |
||||
assertThat(health.getStatus()).isEqualTo(Status.DOWN); |
||||
assertThat(health.getDetails()).contains(entry("error", "java.io.IOException: Couldn't connect")); |
||||
} |
||||
|
||||
@Test |
||||
void elasticsearchIsDownByResponseCode() throws IOException { |
||||
Response response = mock(Response.class); |
||||
StatusLine statusLine = mock(StatusLine.class); |
||||
given(statusLine.getStatusCode()).willReturn(500); |
||||
given(statusLine.getReasonPhrase()).willReturn("Internal server error"); |
||||
given(response.getStatusLine()).willReturn(statusLine); |
||||
given(this.restClient.performRequest(any(Request.class))).willReturn(response); |
||||
Health health = this.elasticsearchRestHealthIndicator.health(); |
||||
assertThat(health.getStatus()).isEqualTo(Status.DOWN); |
||||
assertThat(health.getDetails()).contains(entry("statusCode", 500), |
||||
entry("reasonPhrase", "Internal server error")); |
||||
} |
||||
|
||||
@Test |
||||
void elasticsearchIsOutOfServiceByStatus() throws IOException { |
||||
BasicHttpEntity httpEntity = new BasicHttpEntity(); |
||||
httpEntity.setContent(new ByteArrayInputStream(createJsonResult(200, "red").getBytes())); |
||||
Response response = mock(Response.class); |
||||
StatusLine statusLine = mock(StatusLine.class); |
||||
given(statusLine.getStatusCode()).willReturn(200); |
||||
given(response.getStatusLine()).willReturn(statusLine); |
||||
given(response.getEntity()).willReturn(httpEntity); |
||||
given(this.restClient.performRequest(any(Request.class))).willReturn(response); |
||||
Health health = this.elasticsearchRestHealthIndicator.health(); |
||||
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) { |
||||
if (responseCode == 200) { |
||||
return String.format( |
||||
"{\"cluster_name\":\"elasticsearch\"," |
||||
+ "\"status\":\"%s\",\"timed_out\":false,\"number_of_nodes\":1," |
||||
+ "\"number_of_data_nodes\":1,\"active_primary_shards\":0," |
||||
+ "\"active_shards\":0,\"relocating_shards\":0,\"initializing_shards\":0," |
||||
+ "\"unassigned_shards\":0,\"delayed_unassigned_shards\":0," |
||||
+ "\"number_of_pending_tasks\":0,\"number_of_in_flight_fetch\":0," |
||||
+ "\"task_max_waiting_in_queue_millis\":0,\"active_shards_percent_as_number\":100.0}", |
||||
status); |
||||
} |
||||
return "{\n \"error\": \"Server Error\",\n \"status\": " + responseCode + "\n}"; |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue