Skip to content

Documentation about compatibility headers. #2093

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/main/asciidoc/reference/elasticsearch-clients.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,29 @@ Default is 5 sec.
IMPORTANT: Adding a Header supplier as shown in above example allows to inject headers that may change over the time, like authentication JWT tokens.
If this is used in the reactive setup, the supplier function *must not* block!

=== Elasticsearch 7 compatibility headers

When using Spring Data Elasticsearch 4 - which uses the Elasticsearch 7 client libraries - and accessing an Elasticsearch cluster that is running on version 8, it is necessary to set the compatibility headers
https://www.elastic.co/guide/en/elasticsearch/reference/8.0/rest-api-compatibility.html[see Elasticserach documentation].
This should be done using a header supplier like shown above:

====
[source,java]
----
ClientConfigurationBuilder configurationBuilder = new ClientConfigurationBuilder();
configurationBuilder //
// ...
.withHeaders(() -> {
HttpHeaders defaultCompatibilityHeaders = new HttpHeaders();
defaultCompatibilityHeaders.add("Accept",
"application/vnd.elasticsearch+json;compatible-with=7");
defaultCompatibilityHeaders.add("Content-Type",
"application/vnd.elasticsearch+json;compatible-with=7");
return defaultCompatibilityHeaders;
});
----
====

[[elasticsearch.clients.logging]]
== Client Logging

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@
import java.util.function.Consumer;
import java.util.stream.Stream;

import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.xcontent.XContentType;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
Expand Down Expand Up @@ -66,10 +68,6 @@ void shouldUseConfiguredProxy(ClientUnderTestFactory clientUnderTestFactory, Hov
wireMockServer(server -> {

// wiremock is the dummy server, hoverfly the proxy
WireMock.configureFor(server.port());
stubForElasticsearchVersionCheck();
stubFor(head(urlEqualTo("/")).willReturn(aResponse() //
.withHeader("Content-Type", "application/json; charset=UTF-8")));

String serviceHost = "localhost:" + server.port();
String proxyHost = "localhost:" + hoverfly.getHoverflyConfig().getProxyPort();
Expand All @@ -95,12 +93,6 @@ void shouldUseConfiguredProxy(ClientUnderTestFactory clientUnderTestFactory, Hov
void shouldConfigureClientAndSetAllRequiredHeaders(ClientUnderTestFactory clientUnderTestFactory) {
wireMockServer(server -> {

WireMock.configureFor(server.port());

stubForElasticsearchVersionCheck();
stubFor(head(urlEqualTo("/")).willReturn(aResponse() //
.withHeader("Content-Type", "application/json; charset=UTF-8")));

HttpHeaders defaultHeaders = new HttpHeaders();
defaultHeaders.addAll("def1", Arrays.asList("def1-1", "def1-2"));
defaultHeaders.add("def2", "def2-1");
Expand Down Expand Up @@ -156,6 +148,63 @@ void shouldConfigureClientAndSetAllRequiredHeaders(ClientUnderTestFactory client
});
}

@ParameterizedTest // #2088
@MethodSource("clientUnderTestFactorySource")
@DisplayName("should set compatibility headers")
void shouldSetCompatibilityHeaders(ClientUnderTestFactory clientUnderTestFactory) {

wireMockServer(server -> {

stubFor(put(urlMatching("^/index/_doc/42(\\?.*)$?")) //
.willReturn(jsonResponse("{\n" + //
" \"_id\": \"42\",\n" + //
" \"_index\": \"test\",\n" + //
" \"_primary_term\": 1,\n" + //
" \"_seq_no\": 0,\n" + //
" \"_shards\": {\n" + //
" \"failed\": 0,\n" + //
" \"successful\": 1,\n" + //
" \"total\": 2\n" + //
" },\n" + //
" \"_type\": \"_doc\",\n" + //
" \"_version\": 1,\n" + //
" \"result\": \"created\"\n" + //
"}\n" //
, 201) //
.withHeader("Content-Type", "application/vnd.elasticsearch+json;compatible-with=7") //
.withHeader("X-Elastic-Product", "Elasticsearch")));

ClientConfigurationBuilder configurationBuilder = new ClientConfigurationBuilder();
configurationBuilder //
.connectedTo("localhost:" + server.port()) //
.withHeaders(() -> {
HttpHeaders defaultCompatibilityHeaders = new HttpHeaders();
defaultCompatibilityHeaders.add("Accept", "application/vnd.elasticsearch+json;compatible-with=7");
defaultCompatibilityHeaders.add("Content-Type", "application/vnd.elasticsearch+json;compatible-with=7");
return defaultCompatibilityHeaders;
});

ClientConfiguration clientConfiguration = configurationBuilder.build();
ClientUnderTest clientUnderTest = clientUnderTestFactory.create(clientConfiguration);

class Foo {
public String id;

Foo(String id) {
this.id = id;
}
}
;

clientUnderTest.save(new Foo("42"));

verify(putRequestedFor(urlMatching("^/index/_doc/42(\\?.*)$?")) //
.withHeader("Accept", new EqualToPattern("application/vnd.elasticsearch+json;compatible-with=7")) //
.withHeader("Content-Type", new EqualToPattern("application/vnd.elasticsearch+json;compatible-with=7")) //
);
});
}

private StubMapping stubForElasticsearchVersionCheck() {
return stubFor(get(urlEqualTo("/")) //
.willReturn(okJson("{\n" + //
Expand All @@ -179,6 +228,12 @@ private StubMapping stubForElasticsearchVersionCheck() {
.withHeader("X-Elastic-Product", "Elasticsearch")));
}

private StubMapping stubForHead() {
return stubFor(head(urlEqualTo("/")) //
.willReturn(ok() //
.withHeader("X-Elastic-Product", "Elasticsearch")));
}

/**
* Consumer extension that catches checked exceptions and wraps them in a RuntimeException.
*/
Expand All @@ -198,6 +253,8 @@ default void accept(WireMockServer wiremockConsumer) {

/**
* starts a Wiremock server and calls consumer with the server as argument. Stops the server after consumer execution.
* Before the consumer ids called the {@link #stubForHead()} and {@link #stubForElasticsearchVersionCheck()} are
* registered.
*
* @param consumer the consumer
*/
Expand All @@ -208,6 +265,10 @@ private void wireMockServer(WiremockConsumer consumer) {
// test/resources/mappings
try {
wireMockServer.start();
WireMock.configureFor(wireMockServer.port());
stubForHead();
stubForElasticsearchVersionCheck();

consumer.accept(wireMockServer);
} finally {
wireMockServer.shutdown();
Expand All @@ -224,6 +285,8 @@ interface ClientUnderTest {
* @return true if successful
*/
boolean ping() throws Exception;

<T> void save(T entity) throws IOException;
}

/**
Expand Down Expand Up @@ -253,7 +316,20 @@ protected String getDisplayName() {
@Override
ClientUnderTest create(ClientConfiguration clientConfiguration) {
RestHighLevelClient client = RestClients.create(clientConfiguration).rest();
return () -> client.ping(RequestOptions.DEFAULT);
return new ClientUnderTest() {
@Override
public boolean ping() throws Exception {
return client.ping(RequestOptions.DEFAULT);
}

@Override
public <T> void save(T entity) throws IOException {
IndexRequest indexRequest = new IndexRequest("index");
indexRequest.id("42");
indexRequest.source(entity, XContentType.JSON);
client.index(indexRequest, RequestOptions.DEFAULT);
}
};
}

}
Expand All @@ -271,7 +347,20 @@ protected String getDisplayName() {
@Override
ClientUnderTest create(ClientConfiguration clientConfiguration) {
ReactiveElasticsearchClient client = ReactiveRestClients.create(clientConfiguration);
return () -> client.ping().block();
return new ClientUnderTest() {
@Override
public boolean ping() throws Exception {
return client.ping().block();
}

@Override
public <T> void save(T entity) throws IOException {
IndexRequest indexRequest = new IndexRequest("index");
indexRequest.id("42");
indexRequest.source("{}", XContentType.JSON);
client.index(indexRequest).block();
}
};
}
}

Expand Down