mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-22 12:56:53 +00:00
(cherry picked from commit 475790c34e0bab95d352132d6be63c4f5b219fb1) Signed-off-by: Andrei Dan <andrei.dan@elastic.co>
This commit is contained in:
parent
04b1f6498b
commit
68985bc1ca
@ -55,9 +55,9 @@ import org.elasticsearch.client.indices.GetFieldMappingsRequest;
|
||||
import org.elasticsearch.client.indices.GetFieldMappingsResponse;
|
||||
import org.elasticsearch.client.indices.GetIndexRequest;
|
||||
import org.elasticsearch.client.indices.GetIndexResponse;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplateV2Request;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplatesRequest;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplatesResponse;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplateV2Request;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplatesV2Response;
|
||||
import org.elasticsearch.client.indices.GetMappingsRequest;
|
||||
import org.elasticsearch.client.indices.GetMappingsResponse;
|
||||
@ -70,6 +70,8 @@ import org.elasticsearch.client.indices.ReloadAnalyzersRequest;
|
||||
import org.elasticsearch.client.indices.ReloadAnalyzersResponse;
|
||||
import org.elasticsearch.client.indices.ResizeRequest;
|
||||
import org.elasticsearch.client.indices.ResizeResponse;
|
||||
import org.elasticsearch.client.indices.SimulateIndexTemplateRequest;
|
||||
import org.elasticsearch.client.indices.SimulateIndexTemplateResponse;
|
||||
import org.elasticsearch.client.indices.UnfreezeIndexRequest;
|
||||
import org.elasticsearch.client.indices.rollover.RolloverRequest;
|
||||
import org.elasticsearch.client.indices.rollover.RolloverResponse;
|
||||
@ -1324,6 +1326,40 @@ public final class IndicesClient {
|
||||
options, AcknowledgedResponse::fromXContent, listener, emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulates matching index name against the existing index templates in the system.
|
||||
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-templates.html"> Index Templates API
|
||||
* on elastic.co</a>
|
||||
*
|
||||
* @param simulateIndexTemplateRequest the request
|
||||
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be
|
||||
* customized
|
||||
* @return the response
|
||||
* @throws IOException in case there is a problem sending the request or parsing back the response
|
||||
*/
|
||||
public SimulateIndexTemplateResponse simulateIndexTemplate(SimulateIndexTemplateRequest simulateIndexTemplateRequest,
|
||||
RequestOptions options) throws IOException {
|
||||
return restHighLevelClient.performRequestAndParseEntity(simulateIndexTemplateRequest,
|
||||
IndicesRequestConverters::simulateIndexTemplate, options, SimulateIndexTemplateResponse::fromXContent, emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously simulates matching index name against the existing index templates in the system.
|
||||
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-templates.html"> Index Templates API
|
||||
* on elastic.co</a>
|
||||
*
|
||||
* @param simulateIndexTemplateRequest the request
|
||||
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be
|
||||
* customized
|
||||
* @param listener the listener to be notified upon request completion
|
||||
* @return cancellable that may be used to cancel the request
|
||||
*/
|
||||
public Cancellable simulateIndexTemplateAsync(SimulateIndexTemplateRequest simulateIndexTemplateRequest,
|
||||
RequestOptions options, ActionListener<SimulateIndexTemplateResponse> listener) {
|
||||
return restHighLevelClient.performRequestAsyncAndParseEntity(simulateIndexTemplateRequest,
|
||||
IndicesRequestConverters::simulateIndexTemplate, options, SimulateIndexTemplateResponse::fromXContent, listener, emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a potentially expensive query without executing it.
|
||||
* <p>
|
||||
|
@ -46,8 +46,8 @@ import org.elasticsearch.client.indices.DeleteIndexTemplateV2Request;
|
||||
import org.elasticsearch.client.indices.FreezeIndexRequest;
|
||||
import org.elasticsearch.client.indices.GetFieldMappingsRequest;
|
||||
import org.elasticsearch.client.indices.GetIndexRequest;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplatesRequest;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplateV2Request;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplatesRequest;
|
||||
import org.elasticsearch.client.indices.GetMappingsRequest;
|
||||
import org.elasticsearch.client.indices.IndexTemplateV2ExistRequest;
|
||||
import org.elasticsearch.client.indices.IndexTemplatesExistRequest;
|
||||
@ -56,6 +56,7 @@ import org.elasticsearch.client.indices.PutIndexTemplateV2Request;
|
||||
import org.elasticsearch.client.indices.PutMappingRequest;
|
||||
import org.elasticsearch.client.indices.ReloadAnalyzersRequest;
|
||||
import org.elasticsearch.client.indices.ResizeRequest;
|
||||
import org.elasticsearch.client.indices.SimulateIndexTemplateRequest;
|
||||
import org.elasticsearch.client.indices.UnfreezeIndexRequest;
|
||||
import org.elasticsearch.client.indices.rollover.RolloverRequest;
|
||||
import org.elasticsearch.cluster.metadata.IndexMetadata;
|
||||
@ -603,6 +604,26 @@ final class IndicesRequestConverters {
|
||||
return request;
|
||||
}
|
||||
|
||||
static Request simulateIndexTemplate(SimulateIndexTemplateRequest simulateIndexTemplateRequest) throws IOException {
|
||||
String endpoint = new RequestConverters.EndpointBuilder().addPathPartAsIs("_index_template", "_simulate_index")
|
||||
.addPathPart(simulateIndexTemplateRequest.indexName()).build();
|
||||
Request request = new Request(HttpPost.METHOD_NAME, endpoint);
|
||||
RequestConverters.Params params = new RequestConverters.Params();
|
||||
params.withMasterTimeout(simulateIndexTemplateRequest.masterNodeTimeout());
|
||||
PutIndexTemplateV2Request putIndexTemplateV2Request = simulateIndexTemplateRequest.indexTemplateV2Request();
|
||||
if (putIndexTemplateV2Request != null) {
|
||||
if (putIndexTemplateV2Request.create()) {
|
||||
params.putParam("create", Boolean.TRUE.toString());
|
||||
}
|
||||
if (Strings.hasText(putIndexTemplateV2Request.cause())) {
|
||||
params.putParam("cause", putIndexTemplateV2Request.cause());
|
||||
}
|
||||
request.setEntity(RequestConverters.createEntity(putIndexTemplateV2Request, RequestConverters.REQUEST_BODY_CONTENT_TYPE));
|
||||
}
|
||||
request.addParameters(params.asMap());
|
||||
return request;
|
||||
}
|
||||
|
||||
static Request validateQuery(ValidateQueryRequest validateQueryRequest) throws IOException {
|
||||
String[] indices = validateQueryRequest.indices() == null ? Strings.EMPTY_ARRAY : validateQueryRequest.indices();
|
||||
String[] types = validateQueryRequest.types() == null || indices.length <= 0 ? Strings.EMPTY_ARRAY : validateQueryRequest.types();
|
||||
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you 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
|
||||
*
|
||||
* http://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.elasticsearch.client.indices;
|
||||
|
||||
import org.elasticsearch.client.TimedRequest;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.Strings;
|
||||
|
||||
/**
|
||||
* A request to simulate matching a provided index name and an optional new index template against the existing index templates.
|
||||
*/
|
||||
public class SimulateIndexTemplateRequest extends TimedRequest {
|
||||
|
||||
private String indexName;
|
||||
|
||||
@Nullable
|
||||
private PutIndexTemplateV2Request indexTemplateV2Request;
|
||||
|
||||
public SimulateIndexTemplateRequest(String indexName) {
|
||||
if (Strings.isNullOrEmpty(indexName)) {
|
||||
throw new IllegalArgumentException("index name cannot be null or empty");
|
||||
}
|
||||
this.indexName = indexName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index name for which we simulate the index template matching.
|
||||
*/
|
||||
public String indexName() {
|
||||
return indexName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the index name to simulate template matching against the index templates in the system.
|
||||
*/
|
||||
public SimulateIndexTemplateRequest indexName(String indexName) {
|
||||
if (Strings.isNullOrEmpty(indexName)) {
|
||||
throw new IllegalArgumentException("index name cannot be null or empty");
|
||||
}
|
||||
this.indexName = indexName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* An optional new template request will be part of the index template simulation.
|
||||
*/
|
||||
@Nullable
|
||||
public PutIndexTemplateV2Request indexTemplateV2Request() {
|
||||
return indexTemplateV2Request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optionally, define a new template request which will included in the index simulation as if it was an index template stored in the
|
||||
* system. The new template will be validated just as a regular, standalone, live, new index template request.
|
||||
*/
|
||||
public SimulateIndexTemplateRequest indexTemplateV2Request(@Nullable PutIndexTemplateV2Request indexTemplateV2Request) {
|
||||
this.indexTemplateV2Request = indexTemplateV2Request;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you 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
|
||||
*
|
||||
* http://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.elasticsearch.client.indices;
|
||||
|
||||
import org.elasticsearch.cluster.metadata.Template;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class SimulateIndexTemplateResponse {
|
||||
|
||||
private static final ParseField TEMPLATE = new ParseField("template");
|
||||
private static final ParseField OVERLAPPING = new ParseField("overlapping");
|
||||
private static final ParseField NAME = new ParseField("name");
|
||||
private static final ParseField INDEX_PATTERNS = new ParseField("index_patterns");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final ConstructingObjectParser<SimulateIndexTemplateResponse, Void> PARSER =
|
||||
new ConstructingObjectParser<>("simulate_index_templates_response", false,
|
||||
a -> new SimulateIndexTemplateResponse(
|
||||
a[0] != null ? (Template) a[0] : null,
|
||||
a[1] != null ?
|
||||
((List<IndexTemplateAndPatterns>) a[1]).stream()
|
||||
.collect(Collectors.toMap(IndexTemplateAndPatterns::name, IndexTemplateAndPatterns::indexPatterns)) : null
|
||||
)
|
||||
);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final ConstructingObjectParser<IndexTemplateAndPatterns, Void> INNER_PARSER =
|
||||
new ConstructingObjectParser<>("index_template_and_patterns", false,
|
||||
a -> new IndexTemplateAndPatterns((String) a[0], (List<String>) a[1]));
|
||||
|
||||
private static class IndexTemplateAndPatterns {
|
||||
String name;
|
||||
List<String> indexPatterns;
|
||||
|
||||
IndexTemplateAndPatterns(String name, List<String> indexPatterns) {
|
||||
this.name = name;
|
||||
this.indexPatterns = indexPatterns;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<String> indexPatterns() {
|
||||
return indexPatterns;
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), Template.PARSER, TEMPLATE);
|
||||
INNER_PARSER.declareString(ConstructingObjectParser.constructorArg(), NAME);
|
||||
INNER_PARSER.declareStringArray(ConstructingObjectParser.constructorArg(), INDEX_PATTERNS);
|
||||
PARSER.declareObjectArray(ConstructingObjectParser.optionalConstructorArg(), INNER_PARSER, OVERLAPPING);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
// the resolved settings, mappings and aliases for the matched templates, if any
|
||||
private Template resolvedTemplate;
|
||||
|
||||
@Nullable
|
||||
// a map of template names and their index patterns that would overlap when matching the given index name
|
||||
private Map<String, List<String>> overlappingTemplates;
|
||||
|
||||
SimulateIndexTemplateResponse(@Nullable Template resolvedTemplate, @Nullable Map<String, List<String>> overlappingTemplates) {
|
||||
this.resolvedTemplate = resolvedTemplate;
|
||||
this.overlappingTemplates = overlappingTemplates;
|
||||
}
|
||||
|
||||
public static SimulateIndexTemplateResponse fromXContent(XContentParser parser) throws IOException {
|
||||
return PARSER.parse(parser, null);
|
||||
}
|
||||
|
||||
public Template resolvedTemplate() {
|
||||
return resolvedTemplate;
|
||||
}
|
||||
|
||||
public Map<String, List<String>> overlappingTemplates() {
|
||||
return overlappingTemplates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
SimulateIndexTemplateResponse that = (SimulateIndexTemplateResponse) o;
|
||||
return Objects.equals(resolvedTemplate, that.resolvedTemplate)
|
||||
&& Objects.deepEquals(overlappingTemplates, that.overlappingTemplates);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(resolvedTemplate, overlappingTemplates);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SimulateIndexTemplateResponse{" + "resolved template=" + resolvedTemplate + ", overlapping templates="
|
||||
+ String.join("|", overlappingTemplates.keySet()) + "}";
|
||||
}
|
||||
}
|
@ -68,9 +68,9 @@ import org.elasticsearch.client.indices.GetFieldMappingsRequest;
|
||||
import org.elasticsearch.client.indices.GetFieldMappingsResponse;
|
||||
import org.elasticsearch.client.indices.GetIndexRequest;
|
||||
import org.elasticsearch.client.indices.GetIndexResponse;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplateV2Request;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplatesRequest;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplatesResponse;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplateV2Request;
|
||||
import org.elasticsearch.client.indices.GetIndexTemplatesV2Response;
|
||||
import org.elasticsearch.client.indices.GetMappingsRequest;
|
||||
import org.elasticsearch.client.indices.GetMappingsResponse;
|
||||
@ -82,6 +82,8 @@ import org.elasticsearch.client.indices.PutIndexTemplateV2Request;
|
||||
import org.elasticsearch.client.indices.PutMappingRequest;
|
||||
import org.elasticsearch.client.indices.ReloadAnalyzersRequest;
|
||||
import org.elasticsearch.client.indices.ReloadAnalyzersResponse;
|
||||
import org.elasticsearch.client.indices.SimulateIndexTemplateRequest;
|
||||
import org.elasticsearch.client.indices.SimulateIndexTemplateResponse;
|
||||
import org.elasticsearch.client.indices.UnfreezeIndexRequest;
|
||||
import org.elasticsearch.client.indices.rollover.RolloverRequest;
|
||||
import org.elasticsearch.client.indices.rollover.RolloverResponse;
|
||||
@ -2075,4 +2077,41 @@ public class IndicesClientIT extends ESRestHighLevelClientTestCase {
|
||||
|
||||
assertFalse(exist);
|
||||
}
|
||||
|
||||
public void testSimulateIndexTemplate() throws Exception {
|
||||
String templateName = "my-template";
|
||||
Settings settings = Settings.builder().put("index.number_of_shards", 1).build();
|
||||
CompressedXContent mappings = new CompressedXContent("{\"properties\":{\"host_name\":{\"type\":\"keyword\"}}}");
|
||||
AliasMetadata alias = AliasMetadata.builder("alias").writeIndex(true).build();
|
||||
Template template = new Template(settings, mappings, org.elasticsearch.common.collect.Map.of("alias", alias));
|
||||
List<String> pattern = org.elasticsearch.common.collect.List.of("pattern");
|
||||
IndexTemplateV2 indexTemplate = new IndexTemplateV2(pattern, template, Collections.emptyList(), 1L, 1L, new HashMap<>());
|
||||
PutIndexTemplateV2Request putIndexTemplateV2Request =
|
||||
new PutIndexTemplateV2Request().name(templateName).create(true).indexTemplate(indexTemplate);
|
||||
|
||||
AcknowledgedResponse response = execute(putIndexTemplateV2Request,
|
||||
highLevelClient().indices()::putIndexTemplate, highLevelClient().indices()::putIndexTemplateAsync);
|
||||
assertThat(response.isAcknowledged(), equalTo(true));
|
||||
|
||||
SimulateIndexTemplateRequest simulateIndexTemplateRequest = new SimulateIndexTemplateRequest("pattern");
|
||||
AliasMetadata simulationAlias = AliasMetadata.builder("simulation-alias").writeIndex(true).build();
|
||||
IndexTemplateV2 simulationTemplate = new IndexTemplateV2(pattern, new Template(null, null,
|
||||
org.elasticsearch.common.collect.Map.of("simulation-alias", simulationAlias)), Collections.emptyList(), 2L, 1L,
|
||||
new HashMap<>());
|
||||
PutIndexTemplateV2Request newIndexTemplateReq =
|
||||
new PutIndexTemplateV2Request().name("used-for-simulation").create(true).indexTemplate(indexTemplate);
|
||||
newIndexTemplateReq.indexTemplate(simulationTemplate);
|
||||
simulateIndexTemplateRequest.indexTemplateV2Request(newIndexTemplateReq);
|
||||
|
||||
SimulateIndexTemplateResponse simulateResponse = execute(simulateIndexTemplateRequest,
|
||||
highLevelClient().indices()::simulateIndexTemplate, highLevelClient().indices()::simulateIndexTemplateAsync);
|
||||
|
||||
Map<String, AliasMetadata> aliases = simulateResponse.resolvedTemplate().aliases();
|
||||
assertThat(aliases, is(notNullValue()));
|
||||
assertThat("the template we provided for the simulation has a higher priority than the one in the system",
|
||||
aliases.get("simulation-alias"), is(notNullValue()));
|
||||
assertThat(aliases.get("simulation-alias").getAlias(), is("simulation-alias"));
|
||||
assertThat("existing template overlaps the higher priority template we provided for the simulation",
|
||||
simulateResponse.overlappingTemplates().get("my-template").get(0), is("pattern"));
|
||||
}
|
||||
}
|
||||
|
@ -860,8 +860,7 @@ public class RestHighLevelClientTests extends ESTestCase {
|
||||
"scripts_painless_execute",
|
||||
"indices.create_data_stream",
|
||||
"indices.get_data_streams",
|
||||
"indices.delete_data_stream",
|
||||
"indices.simulate_index_template"
|
||||
"indices.delete_data_stream"
|
||||
};
|
||||
//These API are not required for high-level client feature completeness
|
||||
String[] notRequiredApi = new String[] {
|
||||
|
@ -22,6 +22,16 @@
|
||||
]
|
||||
},
|
||||
"params":{
|
||||
"create":{
|
||||
"type":"boolean",
|
||||
"description":"Whether the index template we optionally defined in the body should only be dry-run added if new or can also replace an existing one",
|
||||
"default":false
|
||||
},
|
||||
"cause":{
|
||||
"type":"string",
|
||||
"description":"User defined reason for dry-run creating the new template for simulation purposes",
|
||||
"default":false
|
||||
},
|
||||
"master_timeout":{
|
||||
"type":"time",
|
||||
"description":"Specify timeout for connection to master"
|
||||
|
@ -53,7 +53,7 @@ public class Template extends AbstractDiffable<Template> implements ToXContentOb
|
||||
private static final ParseField ALIASES = new ParseField("aliases");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static final ConstructingObjectParser<Template, Void> PARSER = new ConstructingObjectParser<>("template", false,
|
||||
public static final ConstructingObjectParser<Template, Void> PARSER = new ConstructingObjectParser<>("template", false,
|
||||
a -> new Template((Settings) a[0], (CompressedXContent) a[1], (Map<String, AliasMetadata>) a[2]));
|
||||
|
||||
static {
|
||||
|
@ -54,6 +54,9 @@ public class RestSimulateIndexTemplateAction extends BaseRestHandler {
|
||||
if (request.hasContent()) {
|
||||
PutIndexTemplateV2Action.Request indexTemplateRequest = new PutIndexTemplateV2Action.Request("simulating_template");
|
||||
indexTemplateRequest.indexTemplate(IndexTemplateV2.parse(request.contentParser()));
|
||||
indexTemplateRequest.create(request.paramAsBoolean("create", false));
|
||||
indexTemplateRequest.cause(request.param("cause", "api"));
|
||||
|
||||
simulateIndexTemplateRequest.indexTemplateRequest(indexTemplateRequest);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user