Skip to content

Commit f5ee74a

Browse files
committed
Add put index template api to high level rest client (#30400)
Relates #27205
1 parent cda131b commit f5ee74a

File tree

11 files changed

+590
-11
lines changed

11 files changed

+590
-11
lines changed

client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsResponse;
5050
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
5151
import org.elasticsearch.action.admin.indices.shrink.ResizeResponse;
52+
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest;
53+
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateResponse;
5254

5355
import java.io.IOException;
5456
import java.util.Collections;
@@ -432,4 +434,26 @@ public void putSettingsAsync(UpdateSettingsRequest updateSettingsRequest, Action
432434
UpdateSettingsResponse::fromXContent, listener, emptySet(), headers);
433435
}
434436

437+
/**
438+
* Puts an index template using the Index Templates API
439+
* <p>
440+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-templates.html"> Index Templates API
441+
* on elastic.co</a>
442+
*/
443+
public PutIndexTemplateResponse putTemplate(PutIndexTemplateRequest putIndexTemplateRequest, Header... headers) throws IOException {
444+
return restHighLevelClient.performRequestAndParseEntity(putIndexTemplateRequest, RequestConverters::putTemplate,
445+
PutIndexTemplateResponse::fromXContent, emptySet(), headers);
446+
}
447+
448+
/**
449+
* Asynchronously puts an index template using the Index Templates API
450+
* <p>
451+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-templates.html"> Index Templates API
452+
* on elastic.co</a>
453+
*/
454+
public void putTemplateAsync(PutIndexTemplateRequest putIndexTemplateRequest,
455+
ActionListener<PutIndexTemplateResponse> listener, Header... headers) {
456+
restHighLevelClient.performRequestAsyncAndParseEntity(putIndexTemplateRequest, RequestConverters::putTemplate,
457+
PutIndexTemplateResponse::fromXContent, listener, emptySet(), headers);
458+
}
435459
}

client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequest;
4747
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
4848
import org.elasticsearch.action.admin.indices.shrink.ResizeType;
49+
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest;
4950
import org.elasticsearch.action.bulk.BulkRequest;
5051
import org.elasticsearch.action.delete.DeleteRequest;
5152
import org.elasticsearch.action.get.GetRequest;
@@ -83,10 +84,7 @@
8384
import java.net.URI;
8485
import java.net.URISyntaxException;
8586
import java.nio.charset.Charset;
86-
import java.util.Collections;
87-
import java.util.HashMap;
8887
import java.util.Locale;
89-
import java.util.Map;
9088
import java.util.StringJoiner;
9189

9290
final class RequestConverters {
@@ -628,6 +626,21 @@ static Request indexPutSettings(UpdateSettingsRequest updateSettingsRequest) thr
628626
return request;
629627
}
630628

629+
static Request putTemplate(PutIndexTemplateRequest putIndexTemplateRequest) throws IOException {
630+
String endpoint = new EndpointBuilder().addPathPartAsIs("_template").addPathPart(putIndexTemplateRequest.name()).build();
631+
Request request = new Request(HttpPut.METHOD_NAME, endpoint);
632+
Params params = new Params(request);
633+
params.withMasterTimeout(putIndexTemplateRequest.masterNodeTimeout());
634+
if (putIndexTemplateRequest.create()) {
635+
params.putParam("create", Boolean.TRUE.toString());
636+
}
637+
if (Strings.hasText(putIndexTemplateRequest.cause())) {
638+
params.putParam("cause", putIndexTemplateRequest.cause());
639+
}
640+
request.setEntity(createEntity(putIndexTemplateRequest, REQUEST_BODY_CONTENT_TYPE));
641+
return request;
642+
}
643+
631644
private static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType) throws IOException {
632645
BytesRef source = XContentHelper.toXContent(toXContent, xContentType, false).toBytesRef();
633646
return new ByteArrayEntity(source.bytes, source.offset, source.length, createContentType(xContentType));

client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,14 @@
5555
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
5656
import org.elasticsearch.action.admin.indices.shrink.ResizeResponse;
5757
import org.elasticsearch.action.admin.indices.shrink.ResizeType;
58+
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest;
59+
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateResponse;
5860
import org.elasticsearch.action.index.IndexRequest;
5961
import org.elasticsearch.action.support.IndicesOptions;
6062
import org.elasticsearch.action.support.WriteRequest;
6163
import org.elasticsearch.action.support.broadcast.BroadcastResponse;
6264
import org.elasticsearch.cluster.metadata.IndexMetaData;
65+
import org.elasticsearch.common.ValidationException;
6366
import org.elasticsearch.common.settings.Setting;
6467
import org.elasticsearch.common.settings.Settings;
6568
import org.elasticsearch.common.unit.ByteSizeUnit;
@@ -72,11 +75,19 @@
7275
import org.elasticsearch.rest.RestStatus;
7376

7477
import java.io.IOException;
78+
import java.util.Arrays;
79+
import java.util.Collections;
7580
import java.util.Map;
7681

7782
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS;
83+
import static org.elasticsearch.common.xcontent.support.XContentMapValues.extractRawValues;
84+
import static org.elasticsearch.common.xcontent.support.XContentMapValues.extractValue;
7885
import static org.hamcrest.CoreMatchers.hasItem;
86+
import static org.hamcrest.Matchers.contains;
87+
import static org.hamcrest.Matchers.containsString;
7988
import static org.hamcrest.Matchers.equalTo;
89+
import static org.hamcrest.Matchers.hasEntry;
90+
import static org.hamcrest.Matchers.hasSize;
8091
import static org.hamcrest.Matchers.not;
8192
import static org.hamcrest.Matchers.startsWith;
8293

@@ -710,4 +721,59 @@ public void testIndexPutSettingNonExistent() throws IOException {
710721
+ "or check the breaking changes documentation for removed settings]"));
711722
}
712723

724+
@SuppressWarnings("unchecked")
725+
public void testPutTemplate() throws Exception {
726+
PutIndexTemplateRequest putTemplateRequest = new PutIndexTemplateRequest()
727+
.name("my-template")
728+
.patterns(Arrays.asList("pattern-1", "name-*"))
729+
.order(10)
730+
.create(randomBoolean())
731+
.settings(Settings.builder().put("number_of_shards", "3").put("number_of_replicas", "0"))
732+
.mapping("doc", "host_name", "type=keyword", "description", "type=text")
733+
.alias(new Alias("alias-1").indexRouting("abc")).alias(new Alias("{index}-write").searchRouting("xyz"));
734+
735+
PutIndexTemplateResponse putTemplateResponse = execute(putTemplateRequest,
736+
highLevelClient().indices()::putTemplate, highLevelClient().indices()::putTemplateAsync);
737+
assertThat(putTemplateResponse.isAcknowledged(), equalTo(true));
738+
739+
Map<String, Object> templates = getAsMap("/_template/my-template");
740+
assertThat(templates.keySet(), hasSize(1));
741+
assertThat(extractValue("my-template.order", templates), equalTo(10));
742+
assertThat(extractRawValues("my-template.index_patterns", templates), contains("pattern-1", "name-*"));
743+
assertThat(extractValue("my-template.settings.index.number_of_shards", templates), equalTo("3"));
744+
assertThat(extractValue("my-template.settings.index.number_of_replicas", templates), equalTo("0"));
745+
assertThat(extractValue("my-template.mappings.doc.properties.host_name.type", templates), equalTo("keyword"));
746+
assertThat(extractValue("my-template.mappings.doc.properties.description.type", templates), equalTo("text"));
747+
assertThat((Map<String, String>) extractValue("my-template.aliases.alias-1", templates), hasEntry("index_routing", "abc"));
748+
assertThat((Map<String, String>) extractValue("my-template.aliases.{index}-write", templates), hasEntry("search_routing", "xyz"));
749+
}
750+
751+
public void testPutTemplateBadRequests() throws Exception {
752+
RestHighLevelClient client = highLevelClient();
753+
754+
// Failed to validate because index patterns are missing
755+
PutIndexTemplateRequest withoutPattern = new PutIndexTemplateRequest("t1");
756+
ValidationException withoutPatternError = expectThrows(ValidationException.class,
757+
() -> execute(withoutPattern, client.indices()::putTemplate, client.indices()::putTemplateAsync));
758+
assertThat(withoutPatternError.validationErrors(), contains("index patterns are missing"));
759+
760+
// Create-only specified but an template exists already
761+
PutIndexTemplateRequest goodTemplate = new PutIndexTemplateRequest("t2").patterns(Arrays.asList("qa-*", "prod-*"));
762+
assertTrue(execute(goodTemplate, client.indices()::putTemplate, client.indices()::putTemplateAsync).isAcknowledged());
763+
goodTemplate.create(true);
764+
ElasticsearchException alreadyExistsError = expectThrows(ElasticsearchException.class,
765+
() -> execute(goodTemplate, client.indices()::putTemplate, client.indices()::putTemplateAsync));
766+
assertThat(alreadyExistsError.getDetailedMessage(),
767+
containsString("[type=illegal_argument_exception, reason=index_template [t2] already exists]"));
768+
goodTemplate.create(false);
769+
assertTrue(execute(goodTemplate, client.indices()::putTemplate, client.indices()::putTemplateAsync).isAcknowledged());
770+
771+
// Rejected due to unknown settings
772+
PutIndexTemplateRequest unknownSettingTemplate = new PutIndexTemplateRequest("t3")
773+
.patterns(Collections.singletonList("any"))
774+
.settings(Settings.builder().put("this-setting-does-not-exist", 100));
775+
ElasticsearchStatusException unknownSettingError = expectThrows(ElasticsearchStatusException.class,
776+
() -> execute(unknownSettingTemplate, client.indices()::putTemplate, client.indices()::putTemplateAsync));
777+
assertThat(unknownSettingError.getDetailedMessage(), containsString("unknown setting [index.this-setting-does-not-exist]"));
778+
}
713779
}

client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,11 @@
2626
import org.apache.http.client.methods.HttpPost;
2727
import org.apache.http.client.methods.HttpPut;
2828
import org.apache.http.entity.ByteArrayEntity;
29-
import org.apache.http.entity.ContentType;
30-
import org.apache.http.entity.StringEntity;
3129
import org.apache.http.util.EntityUtils;
3230
import org.elasticsearch.action.ActionRequestValidationException;
3331
import org.elasticsearch.action.DocWriteRequest;
3432
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
33+
import org.elasticsearch.action.admin.indices.alias.Alias;
3534
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
3635
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
3736
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
@@ -49,6 +48,7 @@
4948
import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequest;
5049
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
5150
import org.elasticsearch.action.admin.indices.shrink.ResizeType;
51+
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest;
5252
import org.elasticsearch.action.bulk.BulkRequest;
5353
import org.elasticsearch.action.bulk.BulkShardRequest;
5454
import org.elasticsearch.action.delete.DeleteRequest;
@@ -68,21 +68,21 @@
6868
import org.elasticsearch.action.support.master.MasterNodeRequest;
6969
import org.elasticsearch.action.support.replication.ReplicationRequest;
7070
import org.elasticsearch.action.update.UpdateRequest;
71+
import org.elasticsearch.client.RequestConverters.EndpointBuilder;
7172
import org.elasticsearch.common.CheckedBiConsumer;
7273
import org.elasticsearch.common.CheckedFunction;
7374
import org.elasticsearch.common.Strings;
7475
import org.elasticsearch.common.bytes.BytesArray;
7576
import org.elasticsearch.common.bytes.BytesReference;
7677
import org.elasticsearch.common.io.Streams;
7778
import org.elasticsearch.common.lucene.uid.Versions;
79+
import org.elasticsearch.common.settings.Settings;
7880
import org.elasticsearch.common.unit.TimeValue;
7981
import org.elasticsearch.common.xcontent.ToXContent;
8082
import org.elasticsearch.common.xcontent.XContentBuilder;
8183
import org.elasticsearch.common.xcontent.XContentHelper;
8284
import org.elasticsearch.common.xcontent.XContentParser;
8385
import org.elasticsearch.common.xcontent.XContentType;
84-
import org.elasticsearch.client.RequestConverters.EndpointBuilder;
85-
import org.elasticsearch.client.RequestConverters.Params;
8686
import org.elasticsearch.index.RandomCreateIndexGenerator;
8787
import org.elasticsearch.index.VersionType;
8888
import org.elasticsearch.index.query.TermQueryBuilder;
@@ -107,9 +107,8 @@
107107

108108
import java.io.IOException;
109109
import java.io.InputStream;
110-
import java.lang.reflect.Constructor;
111-
import java.lang.reflect.Modifier;
112110
import java.util.ArrayList;
111+
import java.util.Arrays;
113112
import java.util.Collections;
114113
import java.util.HashMap;
115114
import java.util.List;
@@ -1368,6 +1367,48 @@ public void testIndexPutSettings() throws IOException {
13681367
assertEquals(expectedParams, request.getParameters());
13691368
}
13701369

1370+
public void testPutTemplateRequest() throws Exception {
1371+
Map<String, String> names = new HashMap<>();
1372+
names.put("log", "log");
1373+
names.put("template#1", "template%231");
1374+
names.put("-#template", "-%23template");
1375+
names.put("foo^bar", "foo%5Ebar");
1376+
1377+
PutIndexTemplateRequest putTemplateRequest = new PutIndexTemplateRequest()
1378+
.name(randomFrom(names.keySet()))
1379+
.patterns(Arrays.asList(generateRandomStringArray(20, 100, false, false)));
1380+
if (randomBoolean()) {
1381+
putTemplateRequest.order(randomInt());
1382+
}
1383+
if (randomBoolean()) {
1384+
putTemplateRequest.version(randomInt());
1385+
}
1386+
if (randomBoolean()) {
1387+
putTemplateRequest.settings(Settings.builder().put("setting-" + randomInt(), randomTimeValue()));
1388+
}
1389+
if (randomBoolean()) {
1390+
putTemplateRequest.mapping("doc-" + randomInt(), "field-" + randomInt(), "type=" + randomFrom("text", "keyword"));
1391+
}
1392+
if (randomBoolean()) {
1393+
putTemplateRequest.alias(new Alias("alias-" + randomInt()));
1394+
}
1395+
Map<String, String> expectedParams = new HashMap<>();
1396+
if (randomBoolean()) {
1397+
expectedParams.put("create", Boolean.TRUE.toString());
1398+
putTemplateRequest.create(true);
1399+
}
1400+
if (randomBoolean()) {
1401+
String cause = randomUnicodeOfCodepointLengthBetween(1, 50);
1402+
putTemplateRequest.cause(cause);
1403+
expectedParams.put("cause", cause);
1404+
}
1405+
setRandomMasterTimeout(putTemplateRequest, expectedParams);
1406+
Request request = RequestConverters.putTemplate(putTemplateRequest);
1407+
assertThat(request.getEndpoint(), equalTo("/_template/" + names.get(putTemplateRequest.name())));
1408+
assertThat(request.getParameters(), equalTo(expectedParams));
1409+
assertToXContentBody(putTemplateRequest, request.getEntity());
1410+
}
1411+
13711412
private static void assertToXContentBody(ToXContent expectedBody, HttpEntity actualEntity) throws IOException {
13721413
BytesReference expectedBytes = XContentHelper.toXContent(expectedBody, REQUEST_BODY_CONTENT_TYPE, false);
13731414
assertEquals(XContentType.JSON.mediaTypeWithoutParameters(), actualEntity.getContentType().getValue());

0 commit comments

Comments
 (0)