Skip to content

Commit 1fe74a6

Browse files
authored
Better error when can't auto create index (#22488)
Changes the error message when `action.auto_create_index` or `index.mapper.dynamic` forbids automatic creation of an index from `no such index` to one of: * `no such index and [action.auto_create_index] is [false]` * `no such index and [index.mapper.dynamic] is [false]` * `no such index and [action.auto_create_index] contains [-<pattern>] which forbids automatic creation of the index` * `no such index and [action.auto_create_index] ([all patterns]) doesn't match` This should make it more clear *why* there is `no such index`. Closes #22435
1 parent cd52065 commit 1fe74a6

File tree

7 files changed

+161
-59
lines changed

7 files changed

+161
-59
lines changed

buildSrc/src/main/resources/checkstyle_suppressions.xml

-1
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,6 @@
168168
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]action[/\\]search[/\\]TransportMultiSearchAction.java" checks="LineLength" />
169169
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]action[/\\]suggest[/\\]SuggestResponse.java" checks="LineLength" />
170170
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]action[/\\]support[/\\]ActionFilter.java" checks="LineLength" />
171-
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]action[/\\]support[/\\]AutoCreateIndex.java" checks="LineLength" />
172171
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]action[/\\]support[/\\]DelegatingActionListener.java" checks="LineLength" />
173172
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]action[/\\]support[/\\]IndicesOptions.java" checks="LineLength" />
174173
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]action[/\\]support[/\\]ToXContentToBytes.java" checks="LineLength" />

core/src/main/java/org/elasticsearch/action/support/AutoCreateIndex.java

+28-10
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.elasticsearch.common.settings.Setting;
3030
import org.elasticsearch.common.settings.Setting.Property;
3131
import org.elasticsearch.common.settings.Settings;
32+
import org.elasticsearch.index.IndexNotFoundException;
3233
import org.elasticsearch.index.mapper.MapperService;
3334

3435
import java.util.ArrayList;
@@ -63,18 +64,20 @@ public boolean needToCheck() {
6364

6465
/**
6566
* Should the index be auto created?
67+
* @throws IndexNotFoundException if the the index doesn't exist and shouldn't be auto created
6668
*/
6769
public boolean shouldAutoCreate(String index, ClusterState state) {
70+
if (resolver.hasIndexOrAlias(index, state)) {
71+
return false;
72+
}
6873
// One volatile read, so that all checks are done against the same instance:
6974
final AutoCreate autoCreate = this.autoCreate;
7075
if (autoCreate.autoCreateIndex == false) {
71-
return false;
76+
throw new IndexNotFoundException("no such index and [" + AUTO_CREATE_INDEX_SETTING.getKey() + "] is [false]", index);
7277
}
7378
if (dynamicMappingDisabled) {
74-
return false;
75-
}
76-
if (resolver.hasIndexOrAlias(index, state)) {
77-
return false;
79+
throw new IndexNotFoundException("no such index and [" + MapperService.INDEX_MAPPER_DYNAMIC_SETTING.getKey() + "] is [false]",
80+
index);
7881
}
7982
// matches not set, default value of "true"
8083
if (autoCreate.expressions.isEmpty()) {
@@ -84,10 +87,15 @@ public boolean shouldAutoCreate(String index, ClusterState state) {
8487
String indexExpression = expression.v1();
8588
boolean include = expression.v2();
8689
if (Regex.simpleMatch(indexExpression, index)) {
87-
return include;
90+
if (include) {
91+
return true;
92+
}
93+
throw new IndexNotFoundException("no such index and [" + AUTO_CREATE_INDEX_SETTING.getKey() + "] contains [-"
94+
+ indexExpression + "] which forbids automatic creation of the index", index);
8895
}
8996
}
90-
return false;
97+
throw new IndexNotFoundException("no such index and [" + AUTO_CREATE_INDEX_SETTING.getKey() + "] ([" + autoCreate
98+
+ "]) doesn't match", index);
9199
}
92100

93101
AutoCreate getAutoCreate() {
@@ -101,6 +109,7 @@ void setAutoCreate(AutoCreate autoCreate) {
101109
static class AutoCreate {
102110
private final boolean autoCreateIndex;
103111
private final List<Tuple<String, Boolean>> expressions;
112+
private final String string;
104113

105114
private AutoCreate(String value) {
106115
boolean autoCreateIndex;
@@ -112,18 +121,21 @@ private AutoCreate(String value) {
112121
String[] patterns = Strings.commaDelimitedListToStringArray(value);
113122
for (String pattern : patterns) {
114123
if (pattern == null || pattern.trim().length() == 0) {
115-
throw new IllegalArgumentException("Can't parse [" + value + "] for setting [action.auto_create_index] must be either [true, false, or a comma separated list of index patterns]");
124+
throw new IllegalArgumentException("Can't parse [" + value + "] for setting [action.auto_create_index] must "
125+
+ "be either [true, false, or a comma separated list of index patterns]");
116126
}
117127
pattern = pattern.trim();
118128
Tuple<String, Boolean> expression;
119129
if (pattern.startsWith("-")) {
120130
if (pattern.length() == 1) {
121-
throw new IllegalArgumentException("Can't parse [" + value + "] for setting [action.auto_create_index] must contain an index name after [-]");
131+
throw new IllegalArgumentException("Can't parse [" + value + "] for setting [action.auto_create_index] "
132+
+ "must contain an index name after [-]");
122133
}
123134
expression = new Tuple<>(pattern.substring(1), false);
124135
} else if(pattern.startsWith("+")) {
125136
if (pattern.length() == 1) {
126-
throw new IllegalArgumentException("Can't parse [" + value + "] for setting [action.auto_create_index] must contain an index name after [+]");
137+
throw new IllegalArgumentException("Can't parse [" + value + "] for setting [action.auto_create_index] "
138+
+ "must contain an index name after [+]");
127139
}
128140
expression = new Tuple<>(pattern.substring(1), true);
129141
} else {
@@ -139,6 +151,7 @@ private AutoCreate(String value) {
139151
}
140152
this.expressions = expressions;
141153
this.autoCreateIndex = autoCreateIndex;
154+
this.string = value;
142155
}
143156

144157
boolean isAutoCreateIndex() {
@@ -148,5 +161,10 @@ boolean isAutoCreateIndex() {
148161
List<Tuple<String, Boolean>> getExpressions() {
149162
return expressions;
150163
}
164+
165+
@Override
166+
public String toString() {
167+
return string;
168+
}
151169
}
152170
}

core/src/main/java/org/elasticsearch/index/IndexNotFoundException.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,16 @@
2424
import java.io.IOException;
2525

2626
public final class IndexNotFoundException extends ResourceNotFoundException {
27+
/**
28+
* Construct with a custom message.
29+
*/
30+
public IndexNotFoundException(String message, String index) {
31+
super(message);
32+
setIndex(index);
33+
}
2734

2835
public IndexNotFoundException(String index) {
29-
this(index, null);
36+
this(index, (Throwable) null);
3037
}
3138

3239
public IndexNotFoundException(String index, Throwable cause) {

core/src/test/java/org/elasticsearch/action/support/AutoCreateIndexTests.java

+34-14
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.elasticsearch.common.collect.Tuple;
2929
import org.elasticsearch.common.settings.ClusterSettings;
3030
import org.elasticsearch.common.settings.Settings;
31+
import org.elasticsearch.index.IndexNotFoundException;
3132
import org.elasticsearch.index.mapper.MapperService;
3233
import org.elasticsearch.test.ESTestCase;
3334

@@ -83,7 +84,9 @@ public void testHandleSpaces() { // see #21449
8384
public void testAutoCreationDisabled() {
8485
Settings settings = Settings.builder().put(AutoCreateIndex.AUTO_CREATE_INDEX_SETTING.getKey(), false).build();
8586
AutoCreateIndex autoCreateIndex = newAutoCreateIndex(settings);
86-
assertThat(autoCreateIndex.shouldAutoCreate(randomAsciiOfLengthBetween(1, 10), buildClusterState()), equalTo(false));
87+
IndexNotFoundException e = expectThrows(IndexNotFoundException.class, () ->
88+
autoCreateIndex.shouldAutoCreate(randomAsciiOfLengthBetween(1, 10), buildClusterState()));
89+
assertEquals("no such index and [action.auto_create_index] is [false]", e.getMessage());
8790
}
8891

8992
public void testAutoCreationEnabled() {
@@ -110,7 +113,9 @@ public void testDynamicMappingDisabled() {
110113
randomAsciiOfLengthBetween(1, 10)))
111114
.put(MapperService.INDEX_MAPPER_DYNAMIC_SETTING.getKey(), false).build();
112115
AutoCreateIndex autoCreateIndex = newAutoCreateIndex(settings);
113-
assertThat(autoCreateIndex.shouldAutoCreate(randomAsciiOfLengthBetween(1, 10), buildClusterState()), equalTo(false));
116+
IndexNotFoundException e = expectThrows(IndexNotFoundException.class, () ->
117+
autoCreateIndex.shouldAutoCreate(randomAsciiOfLengthBetween(1, 10), buildClusterState()));
118+
assertEquals("no such index and [index.mapper.dynamic] is [false]", e.getMessage());
114119
}
115120

116121
public void testAutoCreationPatternEnabled() {
@@ -119,36 +124,37 @@ public void testAutoCreationPatternEnabled() {
119124
AutoCreateIndex autoCreateIndex = newAutoCreateIndex(settings);
120125
ClusterState clusterState = ClusterState.builder(new ClusterName("test")).metaData(MetaData.builder()).build();
121126
assertThat(autoCreateIndex.shouldAutoCreate("index" + randomAsciiOfLengthBetween(1, 5), clusterState), equalTo(true));
122-
assertThat(autoCreateIndex.shouldAutoCreate("does_not_match" + randomAsciiOfLengthBetween(1, 5), clusterState), equalTo(false));
127+
expectNotMatch(clusterState, autoCreateIndex, "does_not_match" + randomAsciiOfLengthBetween(1, 5));
123128
}
124129

125130
public void testAutoCreationPatternDisabled() {
126131
Settings settings = Settings.builder().put(AutoCreateIndex.AUTO_CREATE_INDEX_SETTING.getKey(), "-index*").build();
127132
AutoCreateIndex autoCreateIndex = newAutoCreateIndex(settings);
128133
ClusterState clusterState = ClusterState.builder(new ClusterName("test")).metaData(MetaData.builder()).build();
129-
assertThat(autoCreateIndex.shouldAutoCreate("index" + randomAsciiOfLengthBetween(1, 5), clusterState), equalTo(false));
130-
//default is false when patterns are specified
131-
assertThat(autoCreateIndex.shouldAutoCreate("does_not_match" + randomAsciiOfLengthBetween(1, 5), clusterState), equalTo(false));
134+
expectForbidden(clusterState, autoCreateIndex, "index" + randomAsciiOfLengthBetween(1, 5), "-index*");
135+
/* When patterns are specified, even if the are all negative, the default is can't create. So a pure negative pattern is the same
136+
* as false, really. */
137+
expectNotMatch(clusterState, autoCreateIndex, "does_not_match" + randomAsciiOfLengthBetween(1, 5));
132138
}
133139

134140
public void testAutoCreationMultiplePatternsWithWildcards() {
135141
Settings settings = Settings.builder().put(AutoCreateIndex.AUTO_CREATE_INDEX_SETTING.getKey(),
136142
randomFrom("+test*,-index*", "test*,-index*")).build();
137143
AutoCreateIndex autoCreateIndex = newAutoCreateIndex(settings);
138144
ClusterState clusterState = ClusterState.builder(new ClusterName("test")).metaData(MetaData.builder()).build();
139-
assertThat(autoCreateIndex.shouldAutoCreate("index" + randomAsciiOfLengthBetween(1, 5), clusterState), equalTo(false));
145+
expectForbidden(clusterState, autoCreateIndex, "index" + randomAsciiOfLengthBetween(1, 5), "-index*");
140146
assertThat(autoCreateIndex.shouldAutoCreate("test" + randomAsciiOfLengthBetween(1, 5), clusterState), equalTo(true));
141-
assertThat(autoCreateIndex.shouldAutoCreate("does_not_match" + randomAsciiOfLengthBetween(1, 5), clusterState), equalTo(false));
147+
expectNotMatch(clusterState, autoCreateIndex, "does_not_match" + randomAsciiOfLengthBetween(1, 5));
142148
}
143149

144150
public void testAutoCreationMultiplePatternsNoWildcards() {
145151
Settings settings = Settings.builder().put(AutoCreateIndex.AUTO_CREATE_INDEX_SETTING.getKey(), "+test1,-index1").build();
146152
AutoCreateIndex autoCreateIndex = newAutoCreateIndex(settings);
147153
ClusterState clusterState = ClusterState.builder(new ClusterName("test")).metaData(MetaData.builder()).build();
148154
assertThat(autoCreateIndex.shouldAutoCreate("test1", clusterState), equalTo(true));
149-
assertThat(autoCreateIndex.shouldAutoCreate("index" + randomAsciiOfLengthBetween(1, 5), clusterState), equalTo(false));
150-
assertThat(autoCreateIndex.shouldAutoCreate("test" + randomAsciiOfLengthBetween(2, 5), clusterState), equalTo(false));
151-
assertThat(autoCreateIndex.shouldAutoCreate("does_not_match" + randomAsciiOfLengthBetween(1, 5), clusterState), equalTo(false));
155+
expectNotMatch(clusterState, autoCreateIndex, "index" + randomAsciiOfLengthBetween(1, 5));
156+
expectNotMatch(clusterState, autoCreateIndex, "test" + randomAsciiOfLengthBetween(2, 5));
157+
expectNotMatch(clusterState, autoCreateIndex, "does_not_match" + randomAsciiOfLengthBetween(1, 5));
152158
}
153159

154160
public void testAutoCreationMultipleIndexNames() {
@@ -157,7 +163,7 @@ public void testAutoCreationMultipleIndexNames() {
157163
ClusterState clusterState = ClusterState.builder(new ClusterName("test")).metaData(MetaData.builder()).build();
158164
assertThat(autoCreateIndex.shouldAutoCreate("test1", clusterState), equalTo(true));
159165
assertThat(autoCreateIndex.shouldAutoCreate("test2", clusterState), equalTo(true));
160-
assertThat(autoCreateIndex.shouldAutoCreate("does_not_match" + randomAsciiOfLengthBetween(1, 5), clusterState), equalTo(false));
166+
expectNotMatch(clusterState, autoCreateIndex, "does_not_match" + randomAsciiOfLengthBetween(1, 5));
161167
}
162168

163169
public void testAutoCreationConflictingPatternsFirstWins() {
@@ -166,8 +172,8 @@ public void testAutoCreationConflictingPatternsFirstWins() {
166172
AutoCreateIndex autoCreateIndex = newAutoCreateIndex(settings);
167173
ClusterState clusterState = ClusterState.builder(new ClusterName("test")).metaData(MetaData.builder()).build();
168174
assertThat(autoCreateIndex.shouldAutoCreate("test1", clusterState), equalTo(true));
169-
assertThat(autoCreateIndex.shouldAutoCreate("test2", clusterState), equalTo(false));
170-
assertThat(autoCreateIndex.shouldAutoCreate("does_not_match" + randomAsciiOfLengthBetween(1, 5), clusterState), equalTo(false));
175+
expectForbidden(clusterState, autoCreateIndex, "test2", "-test2");
176+
expectNotMatch(clusterState, autoCreateIndex, "does_not_match" + randomAsciiOfLengthBetween(1, 5));
171177
}
172178

173179
public void testUpdate() {
@@ -208,4 +214,18 @@ private AutoCreateIndex newAutoCreateIndex(Settings settings) {
208214
return new AutoCreateIndex(settings, new ClusterSettings(settings,
209215
ClusterSettings.BUILT_IN_CLUSTER_SETTINGS), new IndexNameExpressionResolver(settings));
210216
}
217+
218+
private void expectNotMatch(ClusterState clusterState, AutoCreateIndex autoCreateIndex, String index) {
219+
IndexNotFoundException e = expectThrows(IndexNotFoundException.class, () ->
220+
autoCreateIndex.shouldAutoCreate(index, clusterState));
221+
assertEquals("no such index and [action.auto_create_index] ([" + autoCreateIndex.getAutoCreate() + "]) doesn't match",
222+
e.getMessage());
223+
}
224+
225+
private void expectForbidden(ClusterState clusterState, AutoCreateIndex autoCreateIndex, String index, String forbiddingPattern) {
226+
IndexNotFoundException e = expectThrows(IndexNotFoundException.class, () ->
227+
autoCreateIndex.shouldAutoCreate(index, clusterState));
228+
assertEquals("no such index and [action.auto_create_index] contains [" + forbiddingPattern
229+
+ "] which forbids automatic creation of the index", e.getMessage());
230+
}
211231
}

core/src/test/java/org/elasticsearch/cluster/NoMasterNodeIT.java

+5-15
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242

4343
import java.util.Collections;
4444

45+
import static org.elasticsearch.common.unit.TimeValue.timeValueSeconds;
4546
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertExists;
4647
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
4748
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertThrows;
@@ -59,13 +60,9 @@ protected Settings nodeSettings(int nodeOrdinal) {
5960
}
6061

6162
public void testNoMasterActions() throws Exception {
62-
// note, sometimes, we want to check with the fact that an index gets created, sometimes not...
63-
boolean autoCreateIndex = randomBoolean();
64-
logger.info("auto_create_index set to {}", autoCreateIndex);
65-
6663
Settings settings = Settings.builder()
6764
.put("discovery.type", "zen")
68-
.put("action.auto_create_index", autoCreateIndex)
65+
.put("action.auto_create_index", true)
6966
.put("discovery.zen.minimum_master_nodes", 2)
7067
.put(ZenDiscovery.PING_TIMEOUT_SETTING.getKey(), "200ms")
7168
.put("discovery.initial_state_timeout", "500ms")
@@ -126,7 +123,7 @@ public void run() {
126123
.setScript(new Script(
127124
ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, "test script", Collections.emptyMap())).setTimeout(timeout));
128125

129-
checkUpdateAction(autoCreateIndex, timeout,
126+
checkUpdateAction(true, timeout,
130127
client().prepareUpdate("no_index", "type1", "1")
131128
.setScript(new Script(
132129
ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, "test script", Collections.emptyMap())).setTimeout(timeout));
@@ -135,7 +132,7 @@ public void run() {
135132
checkWriteAction(false, timeout,
136133
client().prepareIndex("test", "type1", "1").setSource(XContentFactory.jsonBuilder().startObject().endObject()).setTimeout(timeout));
137134

138-
checkWriteAction(autoCreateIndex, timeout,
135+
checkWriteAction(true, timeout,
139136
client().prepareIndex("no_index", "type1", "1").setSource(XContentFactory.jsonBuilder().startObject().endObject()).setTimeout(timeout));
140137

141138
BulkRequestBuilder bulkRequestBuilder = client().prepareBulk();
@@ -149,15 +146,8 @@ public void run() {
149146
bulkRequestBuilder = client().prepareBulk();
150147
bulkRequestBuilder.add(client().prepareIndex("no_index", "type1", "1").setSource(XContentFactory.jsonBuilder().startObject().endObject()));
151148
bulkRequestBuilder.add(client().prepareIndex("no_index", "type1", "2").setSource(XContentFactory.jsonBuilder().startObject().endObject()));
152-
if (autoCreateIndex) {
153-
// we expect the bulk to fail because it will try to go to the master. Use small timeout and detect it has passed
154-
timeout = new TimeValue(200);
155-
} else {
156-
// the request should fail very quickly - use a large timeout and make sure it didn't pass...
157-
timeout = new TimeValue(5000);
158-
}
159149
bulkRequestBuilder.setTimeout(timeout);
160-
checkWriteAction(autoCreateIndex, timeout, bulkRequestBuilder);
150+
checkWriteAction(true, timeValueSeconds(5), bulkRequestBuilder);
161151

162152
internalCluster().startNode(settings);
163153
client().admin().cluster().prepareHealth().setWaitForGreenStatus().setWaitForNodes("2").execute().actionGet();

0 commit comments

Comments
 (0)