Skip to content
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

HLRest: Add get index templates API #31161

Merged
merged 10 commits into from
Jun 11, 2018
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@
import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsResponse;
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeResponse;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesRequest;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest;
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateResponse;

Expand Down Expand Up @@ -1059,4 +1061,28 @@ public void putTemplateAsync(PutIndexTemplateRequest putIndexTemplateRequest, Re
restHighLevelClient.performRequestAsyncAndParseEntity(putIndexTemplateRequest, RequestConverters::putTemplate, options,
PutIndexTemplateResponse::fromXContent, listener, emptySet());
}

/**
* Gets index templates using the Index Templates API
* <p>
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-templates.html"> Index Templates API
* on elastic.co</a>
*/
public GetIndexTemplatesResponse getTemplates(GetIndexTemplatesRequest getIndexTemplatesRequest,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can we call it getTemplate? That's what our SPEC have, without the final 's'

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed 7117a3d

RequestOptions options) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(getIndexTemplatesRequest, RequestConverters::getTemplates,
options, GetIndexTemplatesResponse::fromXContent, emptySet());
}

/**
* Asynchronously gets index templates using the Index Templates API
* <p>
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-templates.html"> Index Templates API
* on elastic.co</a>
*/
public void getTemplatesAsync(GetIndexTemplatesRequest getIndexTemplatesRequest, RequestOptions options,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you improve the javadocs like we have it in the other methods?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed 7117a3d

ActionListener<GetIndexTemplatesResponse> listener) {
restHighLevelClient.performRequestAsyncAndParseEntity(getIndexTemplatesRequest, RequestConverters::getTemplates,
options, GetIndexTemplatesResponse::fromXContent, listener, emptySet());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeType;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesRequest;
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
Expand Down Expand Up @@ -818,6 +819,16 @@ static Request putTemplate(PutIndexTemplateRequest putIndexTemplateRequest) thro
return request;
}

static Request getTemplates(GetIndexTemplatesRequest getIndexTemplatesRequest) throws IOException {
String[] names = getIndexTemplatesRequest.names();
String endpoint = new EndpointBuilder().addPathPartAsIs("_template").addCommaSeparatedPathParts(names).build();
Request request = new Request(HttpGet.METHOD_NAME, endpoint);
Params params = new Params(request);
params.withLocal(getIndexTemplatesRequest.local());
params.withMasterTimeout(getIndexTemplatesRequest.masterNodeTimeout());
return request;
}

private static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType) throws IOException {
BytesRef source = XContentHelper.toXContent(toXContent, xContentType, false).toBytesRef();
return new ByteArrayEntity(source.bytes, source.offset, source.length, createContentType(xContentType));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,16 @@
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeResponse;
import org.elasticsearch.action.admin.indices.shrink.ResizeType;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesRequest;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest;
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.support.broadcast.BroadcastResponse;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
import org.elasticsearch.common.ValidationException;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
Expand Down Expand Up @@ -1002,4 +1005,53 @@ public void testPutTemplateBadRequests() throws Exception {
() -> execute(unknownSettingTemplate, client.indices()::putTemplate, client.indices()::putTemplateAsync));
assertThat(unknownSettingError.getDetailedMessage(), containsString("unknown setting [index.this-setting-does-not-exist]"));
}

public void testGetIndexTemplate() throws Exception {
RestHighLevelClient client = highLevelClient();

PutIndexTemplateRequest putTemplate1 = new PutIndexTemplateRequest().name("template-1")
.patterns(Arrays.asList("pattern-1", "name-1")).alias(new Alias("alias-1"));
assertThat(execute(putTemplate1, client.indices()::putTemplate, client.indices()::putTemplateAsync).isAcknowledged(),
equalTo(true));
PutIndexTemplateRequest putTemplate2 = new PutIndexTemplateRequest().name("template-2")
.patterns(Arrays.asList("pattern-2", "name-2"))
.settings(Settings.builder().put("number_of_shards", "2").put("number_of_replicas", "0"));
assertThat(execute(putTemplate2, client.indices()::putTemplate, client.indices()::putTemplateAsync).isAcknowledged(),
equalTo(true));

GetIndexTemplatesResponse getTemplate1 = execute(new GetIndexTemplatesRequest().names("template-1"),
client.indices()::getTemplates, client.indices()::getTemplatesAsync);
assertThat(getTemplate1.getIndexTemplates(), hasSize(1));
IndexTemplateMetaData template1 = getTemplate1.getIndexTemplates().get(0);
assertThat(template1.name(), equalTo("template-1"));
assertThat(template1.patterns(), contains("pattern-1", "name-1"));
assertTrue(template1.aliases().containsKey("alias-1"));

GetIndexTemplatesResponse getTemplate2 = execute(new GetIndexTemplatesRequest().names("template-2"),
client.indices()::getTemplates, client.indices()::getTemplatesAsync);
assertThat(getTemplate2.getIndexTemplates(), hasSize(1));
IndexTemplateMetaData template2 = getTemplate2.getIndexTemplates().get(0);
assertThat(template2.name(), equalTo("template-2"));
assertThat(template2.patterns(), contains("pattern-2", "name-2"));
assertTrue(template2.aliases().isEmpty());
assertThat(template2.settings().get("index.number_of_shards"), equalTo("2"));
assertThat(template2.settings().get("index.number_of_replicas"), equalTo("0"));

GetIndexTemplatesRequest getBothRequest = new GetIndexTemplatesRequest();
if (randomBoolean()) {
getBothRequest.names("*-1", "template-2");
} else {
getBothRequest.names("template-*");
}
GetIndexTemplatesResponse getBoth = execute(getBothRequest, client.indices()::getTemplates, client.indices()::getTemplatesAsync);
assertThat(getBoth.getIndexTemplates(), hasSize(2));
assertThat(getBoth.getIndexTemplates().get(0).name(), equalTo("template-1"));
assertThat(getBoth.getIndexTemplates().get(0).patterns(), contains("pattern-1", "name-1"));
assertThat(getBoth.getIndexTemplates().get(1).name(), equalTo("template-2"));
assertThat(getBoth.getIndexTemplates().get(1).patterns(), contains("pattern-2", "name-2"));

ElasticsearchException notFound = expectThrows(ElasticsearchException.class, () -> execute(
new GetIndexTemplatesRequest().names("the-template-*"), client.indices()::getTemplates, client.indices()::getTemplatesAsync));
assertThat(notFound.status(), equalTo(RestStatus.NOT_FOUND));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeType;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesRequest;
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkShardRequest;
Expand Down Expand Up @@ -140,6 +141,7 @@
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import static java.util.Collections.singletonMap;
import static org.elasticsearch.client.RequestConverters.REQUEST_BODY_CONTENT_TYPE;
Expand Down Expand Up @@ -1762,6 +1764,24 @@ public void testPutTemplateRequest() throws Exception {
assertToXContentBody(putTemplateRequest, request.getEntity());
}

public void testGetTemplateRequest() throws Exception {
Map<String, String> encodes = new HashMap<>();
encodes.put("log", "log");
encodes.put("1", "1");
encodes.put("template#1", "template%231");
encodes.put("template-*", "template-*");
encodes.put("foo^bar", "foo%5Ebar");
List<String> names = randomSubsetOf(1, encodes.keySet());
GetIndexTemplatesRequest getTemplatesRequest = new GetIndexTemplatesRequest().names(names.toArray(new String[0]));
Map<String, String> expectedParams = new HashMap<>();
setRandomMasterTimeout(getTemplatesRequest, expectedParams);
setRandomLocal(getTemplatesRequest, expectedParams);
Request request = RequestConverters.getTemplates(getTemplatesRequest);
assertThat(request.getEndpoint(), equalTo("/_template/" + names.stream().map(encodes::get).collect(Collectors.joining(","))));
assertThat(request.getParameters(), equalTo(expectedParams));
assertThat(request.getEntity(), nullValue());
}

private static void assertToXContentBody(ToXContent expectedBody, HttpEntity actualEntity) throws IOException {
BytesReference expectedBytes = XContentHelper.toXContent(expectedBody, REQUEST_BODY_CONTENT_TYPE, false);
assertEquals(XContentType.JSON.mediaTypeWithoutParameters(), actualEntity.getContentType().getValue());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeResponse;
import org.elasticsearch.action.admin.indices.shrink.ResizeType;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesRequest;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest;
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateResponse;
import org.elasticsearch.action.support.ActiveShardCount;
Expand All @@ -67,6 +69,7 @@
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.SyncedFlushResponse;
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
import org.elasticsearch.cluster.metadata.MappingMetaData;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.settings.Settings;
Expand All @@ -82,11 +85,13 @@
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;

/**
* This class is used to generate the Java Indices API documentation.
Expand Down Expand Up @@ -1983,4 +1988,71 @@ public void onFailure(Exception e) {

assertTrue(latch.await(30L, TimeUnit.SECONDS));
}

public void testGetTemplates() throws Exception {
RestHighLevelClient client = highLevelClient();
{
PutIndexTemplateRequest putRequest = new PutIndexTemplateRequest("my-template");
putRequest.patterns(Arrays.asList("pattern-1", "log-*"));
putRequest.settings(Settings.builder().put("index.number_of_shards", 3).put("index.number_of_replicas", 1));
putRequest.mapping("tweet",
"{\n" +
" \"tweet\": {\n" +
" \"properties\": {\n" +
" \"message\": {\n" +
" \"type\": \"text\"\n" +
" }\n" +
" }\n" +
" }\n" +
"}", XContentType.JSON);
assertTrue(client.indices().putTemplate(putRequest, RequestOptions.DEFAULT).isAcknowledged());
}

// tag::get-templates-request
GetIndexTemplatesRequest request = new GetIndexTemplatesRequest("my-template"); // <1>
request.names("template-1", "template-2"); // <2>
request.names("my-*"); // <3>
// end::get-templates-request

// tag::get-templates-request-masterTimeout
request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1>
request.masterNodeTimeout("1m"); // <2>
// end::get-templates-request-masterTimeout

// tag::get-templates-execute
GetIndexTemplatesResponse getTemplatesResponse = client.indices().getTemplates(request, RequestOptions.DEFAULT);
// end::get-templates-execute

// tag::get-templates-response
List<IndexTemplateMetaData> templates = getTemplatesResponse.getIndexTemplates(); // <1>
// end::get-templates-response

assertThat(templates, hasSize(1));
assertThat(templates.get(0).name(), equalTo("my-template"));

// tag::get-templates-execute-listener
ActionListener<GetIndexTemplatesResponse> listener =
new ActionListener<GetIndexTemplatesResponse>() {
@Override
public void onResponse(GetIndexTemplatesResponse response) {
// <1>
}

@Override
public void onFailure(Exception e) {
// <2>
}
};
// end::get-templates-execute-listener

// Replace the empty listener by a blocking listener in test
final CountDownLatch latch = new CountDownLatch(1);
listener = new LatchedActionListener<>(listener, latch);

// tag::get-templates-execute-async
client.indices().getTemplatesAsync(request, RequestOptions.DEFAULT, listener); // <1>
// end::get-templates-execute-async

assertTrue(latch.await(30L, TimeUnit.SECONDS));
}
}
73 changes: 73 additions & 0 deletions docs/java-rest/high-level/indices/get_templates.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
[[java-rest-high-get-templates]]
=== Get Templates API

The Get Templates API allows to retrieve a list of index templates by name.

[[java-rest-high-get-templates-request]]
==== Get Index Templates Request

A `GetIndexTemplatesRequest` specifies one or several names of the getting index templates.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe better "of the index templates to get"


["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[get-templates-request]
--------------------------------------------------
<1> A single index template name
<2> Multiple index templates' names
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also just use singular "template" here

<3> An index template's name using wildcard
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here


["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[get-templates-request-masterTimeout]
--------------------------------------------------
<1> Timeout to connect to the master node as a `TimeValue`
<2> Timeout to connect to the master node as a `String`

[[java-rest-high-get-templates-sync]]
==== Synchronous Execution

["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[get-templates-execute]
--------------------------------------------------

[[java-rest-high-get-templates-async]]
==== Asynchronous Execution

The asynchronous execution of a get index templates request requires a `GetTemplatesRequest`
instance and an `ActionListener` instance to be passed to the asynchronous
method:

["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[get-templates-execute-async]
--------------------------------------------------
<1> The `GetTemplatesRequest` to execute and the `ActionListener` to use when
the execution completes

The asynchronous method does not block and returns immediately. Once it is
completed the `ActionListener` is called back using the `onResponse` method
if the execution successfully completed or using the `onFailure` method if
it failed.

A typical listener for `GetTemplatesResponse` looks like:

["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[get-templates-execute-listener]
--------------------------------------------------
<1> Called when the execution is successfully completed. The response is
provided as an argument
<2> Called in case of failure. The raised exception is provided as an argument

[[java-rest-high-get-templates-response]]
==== Get Templates Response

The returned `GetTemplatesResponse` consists a list of matching index templates.

["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[get-templates-response]
--------------------------------------------------
<1> A list of matching index templates

1 change: 1 addition & 0 deletions docs/java-rest/high-level/supported-apis.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ include::indices/exists_alias.asciidoc[]
include::indices/put_settings.asciidoc[]
include::indices/get_settings.asciidoc[]
include::indices/put_template.asciidoc[]
include::indices/get_templates.asciidoc[]

== Cluster APIs

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import static java.util.Collections.singletonMap;
Expand All @@ -37,6 +39,7 @@ public class GetIndexTemplatesResponse extends ActionResponse implements ToXCont
private List<IndexTemplateMetaData> indexTemplates;

GetIndexTemplatesResponse() {
indexTemplates = new ArrayList<>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this enable us to make the indexTemplates list final?

}

GetIndexTemplatesResponse(List<IndexTemplateMetaData> indexTemplates) {
Expand Down Expand Up @@ -76,4 +79,16 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
builder.endObject();
return builder;
}

public static GetIndexTemplatesResponse fromXContent(XContentParser parser) throws IOException {
final List<IndexTemplateMetaData> templates = new ArrayList<>();
for (XContentParser.Token token = parser.nextToken(); token != XContentParser.Token.END_OBJECT; token = parser.nextToken()) {
if (token == XContentParser.Token.FIELD_NAME) {
final IndexTemplateMetaData templateMetaData = IndexTemplateMetaData.Builder.fromXContent(parser, parser.currentName());
templates.add(templateMetaData);
}
}
templates.sort(Comparator.comparing(IndexTemplateMetaData::name));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is sorting necessary here? From the way the templates are rendered in toXContent it looks to me we could just read them back the same way?

return new GetIndexTemplatesResponse(templates);
}
}
Loading