Skip to content

Commit

Permalink
Add a template parameter to override auto_create_index value (#61858)
Browse files Browse the repository at this point in the history
Closes #20640.

This PR introduces a new parameter to v2 templates, `allow_auto_create`,
which allows templates to override the cluster setting `auto_create_index`.
Notes:

   * `AutoCreateIndex` now looks for a matching v2 template, and if its
     `allow_auto_create` setting is true, it overrides the usual logic.
   * `TransportBulkAction` previously used `AutoCreateIndex` to check
     whether missing indices should be created. We now rely on
     `AutoCreateAction`, which was already differentiating between creating
     indices and creating data streams.  I've updated `AutoCreateAction` to
     use `AutoCreateIndex`. Data streams are also influenced by
     `allow_auto_create`, in that their default auto-create behaviour can
     be disabled with this setting.
   * Most of the Java file changes are due to introducing an extra
     constructor parameter to `ComposableIndexTemplate`.
   * I've added the new setting to various x-pack templates
   * I added a YAML test to check that watches can be created even when
     `auto_create_index` is `false`.
  • Loading branch information
pugnascotia committed Oct 26, 2020
1 parent 8fc90c7 commit dc855ad
Show file tree
Hide file tree
Showing 46 changed files with 732 additions and 301 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1579,7 +1579,7 @@ public void testDataStreams() throws Exception {
CompressedXContent mappings = new CompressedXContent("{\"properties\":{\"@timestamp\":{\"type\":\"date\"}}}");
Template template = new Template(null, mappings, null);
ComposableIndexTemplate indexTemplate = new ComposableIndexTemplate(Collections.singletonList(dataStreamName), template,
Collections.emptyList(), 1L, 1L, new HashMap<>(), new ComposableIndexTemplate.DataStreamTemplate());
Collections.emptyList(), 1L, 1L, new HashMap<>(), new ComposableIndexTemplate.DataStreamTemplate(), null);
PutComposableIndexTemplateRequest putComposableIndexTemplateRequest =
new PutComposableIndexTemplateRequest().name("ds-template").create(true).indexTemplate(indexTemplate);
AcknowledgedResponse response = execute(putComposableIndexTemplateRequest,
Expand Down Expand Up @@ -1658,7 +1658,7 @@ public void testIndexTemplates() throws Exception {
Template template = new Template(settings, mappings, Map.of("alias", alias));
List<String> pattern = List.of("pattern");
ComposableIndexTemplate indexTemplate =
new ComposableIndexTemplate(pattern, template, Collections.emptyList(), 1L, 1L, new HashMap<>(), null);
new ComposableIndexTemplate(pattern, template, Collections.emptyList(), 1L, 1L, new HashMap<>(), null, null);
PutComposableIndexTemplateRequest putComposableIndexTemplateRequest =
new PutComposableIndexTemplateRequest().name(templateName).create(true).indexTemplate(indexTemplate);

Expand Down Expand Up @@ -1705,7 +1705,7 @@ public void testSimulateIndexTemplate() throws Exception {
Template template = new Template(settings, mappings, Map.of("alias", alias));
List<String> pattern = List.of("pattern");
ComposableIndexTemplate indexTemplate =
new ComposableIndexTemplate(pattern, template, Collections.emptyList(), 1L, 1L, new HashMap<>(), null);
new ComposableIndexTemplate(pattern, template, Collections.emptyList(), 1L, 1L, new HashMap<>(), null, null);
PutComposableIndexTemplateRequest putComposableIndexTemplateRequest =
new PutComposableIndexTemplateRequest().name(templateName).create(true).indexTemplate(indexTemplate);

Expand All @@ -1716,7 +1716,7 @@ public void testSimulateIndexTemplate() throws Exception {
SimulateIndexTemplateRequest simulateIndexTemplateRequest = new SimulateIndexTemplateRequest("pattern");
AliasMetadata simulationAlias = AliasMetadata.builder("simulation-alias").writeIndex(true).build();
ComposableIndexTemplate simulationTemplate = new ComposableIndexTemplate(pattern, new Template(null, null,
Map.of("simulation-alias", simulationAlias)), Collections.emptyList(), 2L, 1L, new HashMap<>(), null);
Map.of("simulation-alias", simulationAlias)), Collections.emptyList(), 2L, 1L, new HashMap<>(), null, null);
PutComposableIndexTemplateRequest newIndexTemplateReq =
new PutComposableIndexTemplateRequest().name("used-for-simulation").create(true).indexTemplate(indexTemplate);
newIndexTemplateReq.indexTemplate(simulationTemplate);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,6 @@ private static ComposableIndexTemplate randomIndexTemplate() {
if (randomBoolean()) {
dataStreamTemplate = new ComposableIndexTemplate.DataStreamTemplate();
}
return new ComposableIndexTemplate(patterns, randomTemplate(), composedOf, priority, version, meta, dataStreamTemplate);
return new ComposableIndexTemplate(patterns, randomTemplate(), composedOf, priority, version, meta, dataStreamTemplate, null);
}
}
28 changes: 19 additions & 9 deletions docs/reference/indices/put-component-template.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
<titleabbrev>Put component template</titleabbrev>
++++

Creates or updates a component template.
Component templates are building blocks for constructing <<indices-templates,index templates>>.
that specify index <<mapping,mappings>>, <<index-modules-settings,settings>>,
and <<indices-aliases,aliases>>.
Creates or updates a component template.
Component templates are building blocks for constructing <<indices-templates,index templates>>.
that specify index <<mapping,mappings>>, <<index-modules-settings,settings>>,
and <<indices-aliases,aliases>>.

[source,console]
--------------------------------------------------
Expand Down Expand Up @@ -55,10 +55,10 @@ DELETE _component_template/template_*
[[put-component-template-api-desc]]
==== {api-description-title}

An index template can be composed of multiple component templates.
An index template can be composed of multiple component templates.
To use a component template, specify it in an index template's `composed_of` list.
Component templates are only applied to new data streams and indices
as part of a matching index template.
Component templates are only applied to new data streams and indices
as part of a matching index template.

Settings and mappings specified directly in the index template or the <<indices-create-index, create index>>
request override any settings or mappings specified in a component template.
Expand Down Expand Up @@ -112,6 +112,16 @@ include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=settings]
Version number used to manage component templates externally.
This number is not automatically generated or incremented by {es}.

`allow_auto_create`::
(Optional, boolean)
This setting overrides the value of the
<<index-creation,`action.auto_create_index`>> cluster setting. If set to
`true` in a template, then indices can be automatically created using that
template even if auto-creation of indices is disabled via
`actions.auto_create_index`. If set to `false`, then indices or data streams matching the
template must always be explicitly created, and may never be automatically
created.

`_meta`::
(Optional, object)
Optional user metadata about the component template. May have any contents.
Expand Down Expand Up @@ -157,7 +167,7 @@ To be applied, a component template must be included in an index template's `com
[[component-templates-version]]
===== Component template versioning

You can use the `version` parameter to add a version number to a component template.
You can use the `version` parameter to add a version number to a component template.
External systems can use these version numbers to simplify template management.

The `version` parameter is optional and not automatically generated or used by {es}.
Expand All @@ -182,7 +192,7 @@ To check the `version`, you can use the <<getting-component-templates,get compon
[[component-templates-metadata]]
===== Component template metadata

You can use the `_meta` parameter to add arbitrary metadata to a component template.
You can use the `_meta` parameter to add arbitrary metadata to a component template.
This user-defined object is stored in the cluster state,
so keeping it short is preferrable.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* 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.http;

import org.elasticsearch.action.support.AutoCreateIndex;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.test.rest.ESRestTestCase;

import java.io.IOException;
import java.io.InputStreamReader;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.hamcrest.Matchers.containsString;

public class AutoCreateIndexIT extends ESRestTestCase {

/**
* Check that setting {@link AutoCreateIndex#AUTO_CREATE_INDEX_SETTING} to <code>false</code>
* disable the automatic creation on indices.
*/
public void testCannotAutoCreateIndexWhenDisabled() throws IOException {
configureAutoCreateIndex(false);

// Attempt to add a document to a non-existing index. Auto-creating the index should fail owing to the setting above.
final Request indexDocumentRequest = new Request("POST", "recipe_kr/_doc/123456");
indexDocumentRequest.setJsonEntity("{ \"name\": \"Kimchi\" }");
final ResponseException responseException = expectThrows(ResponseException.class, this::indexDocument);

assertThat(
Streams.copyToString(new InputStreamReader(responseException.getResponse().getEntity().getContent(), UTF_8)),
containsString("no such index [recipe_kr] and [action.auto_create_index] is [false]")
);
}

/**
* Check that automatically creating an index is allowed, even when {@link AutoCreateIndex#AUTO_CREATE_INDEX_SETTING}
* is <code>false</code>, when the index name matches a template and that template has <code>allow_auto_create</code>
* set to <code>true</code>.
*/
public void testCanAutoCreateIndexWhenAllowedByTemplate() throws IOException {
configureAutoCreateIndex(false);

createTemplateWithAllowAutoCreate(true);

// Attempt to add a document to a non-existing index. Auto-creating the index should succeed because the index name
// matches the template pattern
assertOK(this.indexDocument());
}

/**
* Check that automatically creating an index is disallowed when the index name matches a template and that template has
* <code>allow_auto_create</code> explicitly to <code>false</code>, even when {@link AutoCreateIndex#AUTO_CREATE_INDEX_SETTING}
* is set to <code>true</code>.
*/
public void testCannotAutoCreateIndexWhenDisallowedByTemplate() throws IOException {
configureAutoCreateIndex(true);

createTemplateWithAllowAutoCreate(false);

// Attempt to add a document to a non-existing index. Auto-creating the index should succeed because the index name
// matches the template pattern
final ResponseException responseException = expectThrows(ResponseException.class, this::indexDocument);

assertThat(
Streams.copyToString(new InputStreamReader(responseException.getResponse().getEntity().getContent(), UTF_8)),
containsString("no such index [composable template [recipe*] forbids index auto creation]")
);
}


private void configureAutoCreateIndex(boolean value) throws IOException {
XContentBuilder builder = JsonXContent.contentBuilder()
.startObject()
.startObject("transient")
.field(AutoCreateIndex.AUTO_CREATE_INDEX_SETTING.getKey(), value)
.endObject()
.endObject();

final Request settingsRequest = new Request("PUT", "_cluster/settings");
settingsRequest.setJsonEntity(Strings.toString(builder));
final Response settingsResponse = client().performRequest(settingsRequest);
assertOK(settingsResponse);
}

private void createTemplateWithAllowAutoCreate(Boolean allowAutoCreate) throws IOException {
XContentBuilder builder = JsonXContent.contentBuilder()
.startObject()
.array("index_patterns", "recipe*")
.field("allow_auto_create", allowAutoCreate)
.endObject();

final Request createTemplateRequest = new Request("PUT", "_index_template/recipe_template");
createTemplateRequest.setJsonEntity(Strings.toString(builder));
final Response createTemplateResponse = client().performRequest(createTemplateRequest);
assertOK(createTemplateResponse);
}

private Response indexDocument() throws IOException {
final Request indexDocumentRequest = new Request("POST", "recipe_kr/_doc/123456");
indexDocumentRequest.setJsonEntity("{ \"name\": \"Kimchi\" }");
return client().performRequest(indexDocumentRequest);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ public void testBulkProcessorAutoCreateRestrictions() {
assertTrue("Missing index should have been flagged", responses[1].isFailed());
assertThat(
responses[1].getFailureMessage(),
equalTo("[wontwork] org.elasticsearch.index.IndexNotFoundException: no such index [wontwork]"));
equalTo("[wontwork] org.elasticsearch.index.IndexNotFoundException: no such index [wontwork]"
+ " and [action.auto_create_index] is [false]"));
assertFalse("Operation on existing index should succeed", responses[2].isFailed());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public void testUsageOfDataStreamFails() throws IOException {
Exception expectedException = expectThrows(Exception.class, () -> ComposableIndexTemplate.parse(parser));

ComposableIndexTemplate template = new ComposableIndexTemplate(List.of("logs-*-*"), null, null, null, null,
null, new ComposableIndexTemplate.DataStreamTemplate());
null, new ComposableIndexTemplate.DataStreamTemplate(), null);
Exception e = expectThrows(IllegalArgumentException.class, () -> client().execute(PutComposableIndexTemplateAction.INSTANCE,
new PutComposableIndexTemplateAction.Request("my-it").indexTemplate(template)).actionGet());
Exception actualException = (Exception) e.getCause();
Expand Down

0 comments on commit dc855ad

Please sign in to comment.